From c4a485e5302fed586e53ebdd60b605e02c205178 Mon Sep 17 00:00:00 2001 From: Jacek Pyziak Date: Wed, 6 May 2026 23:16:47 +0200 Subject: [PATCH] update --- .paul/HANDOFF-2026-05-06.md | 113 ++++ .paul/ROADMAP.md | 7 +- .paul/STATE.md | 25 +- .paul/changelog/2026-05-06.md | 35 ++ .paul/governance/governance_2026-05-06.jsonl | 86 +++ .paul/phases/09-finalizacja/09-02-PLAN.md | 325 +++++++++++ .paul/phases/09-finalizacja/09-02-SUMMARY.md | 170 ++++++ .paul/phases/09-finalizacja/09-03-PLAN.md | 440 +++++++++++++++ .paul/phases/09-finalizacja/09-03-SUMMARY.md | 184 +++++++ .vscode/ftp-kr.sync.cache.json | 208 +++++++ .../admin/class-admin.php | 398 ++++++------- .../admin/class-yacht-list-table.php | 23 - .../admin/views/yacht-edit.php | 99 +--- .../includes/class-installer.php | 103 +++- .../includes/class-yacht-booking.php | 13 +- .../includes/class-yacht.php | 28 +- .../google-calendar/class-gcal-service.php | 521 ------------------ .../google-calendar/class-oauth-handler.php | 270 --------- .../google-calendar/class-sync-controller.php | 377 ------------- .../integrations/ical/class-ical-feed.php | 95 ++-- .../integrations/ical/class-ical-import.php | 367 ++++++------ .../yacht-booking-system/uninstall.php | 16 +- .../yacht-booking-system.php | 10 +- 23 files changed, 2141 insertions(+), 1772 deletions(-) create mode 100644 .paul/HANDOFF-2026-05-06.md create mode 100644 .paul/phases/09-finalizacja/09-02-PLAN.md create mode 100644 .paul/phases/09-finalizacja/09-02-SUMMARY.md create mode 100644 .paul/phases/09-finalizacja/09-03-PLAN.md create mode 100644 .paul/phases/09-finalizacja/09-03-SUMMARY.md create mode 100644 .vscode/ftp-kr.sync.cache.json delete mode 100644 wp-content/plugins/yacht-booking-system/integrations/google-calendar/class-gcal-service.php delete mode 100644 wp-content/plugins/yacht-booking-system/integrations/google-calendar/class-oauth-handler.php delete mode 100644 wp-content/plugins/yacht-booking-system/integrations/google-calendar/class-sync-controller.php diff --git a/.paul/HANDOFF-2026-05-06.md b/.paul/HANDOFF-2026-05-06.md new file mode 100644 index 0000000..eb9fa80 --- /dev/null +++ b/.paul/HANDOFF-2026-05-06.md @@ -0,0 +1,113 @@ +# PAUL Handoff + +**Date:** 2026-05-06 +**Status:** paused (end of productive session) + +--- + +## READ THIS FIRST + +You have no prior context. This document tells you everything. + +**Project:** jachty3.pagedev.pl — WordPress plugin `yacht-booking-system` (rezerwacje jachtów z dwukierunkową synchronizacją Google Calendar przez iCal) +**Core value:** Klienci mogą sprawdzić dostępność jachtu i złożyć rezerwację przez stronę bez kontaktu z właścicielem. + +--- + +## Current State + +**Version:** 1.0.0 (Beta → szybko zbliża się do v1.0 production) +**Milestone:** v1.0 Production Release — 92% +**Phase:** 9 of 9 — Finalizacja (60%, 3/5 planów) +**Plan:** 09-03 — **Complete** (loop closed) + +**Loop Position:** +``` +PLAN ──▶ APPLY ──▶ UNIFY + ✓ ✓ ✓ [Loop 09-03 complete, ready for 09-04] +``` + +--- + +## What Was Done (sesja 2026-05-06) + +Sesja zaczęła z: zamkniętą pętlą 09-01 (UX/UI kalendarza). Wykonano 2 pełne pętle PLAN→APPLY→UNIFY: + +### Pętla 09-02 — Globalna synchronizacja iCal +- Wprowadzono dwukierunkową synchronizację z **jednym wspólnym Google Calendar** (przez iCal feed, bez OAuth) +- Globalny iCal Export feed: `/yacht-ical-global/{token}.ics` — wszystkie rezerwacje w jednym pliku, każdy event z prefiksem `"{nazwa_jachtu} - {klient}"` +- Globalny iCal Import — parser dopasowuje prefiks przed `" - "` do `post_title` lub `_yacht_gcal_alias` (case-insensitive, mb_*) +- Anti-loop (eventy z source `ical_import_global` nie są re-eksportowane), stale cleanup, idempotencja po UID +- Pole `_yacht_gcal_alias` w yacht-edit (krótki alias jak "Maja" zamiast pełnej nazwy) +- Settings UI: nowa sekcja "Globalna synchronizacja iCal" + +### Pętla 09-03 — Cleanup OAuth + per-yacht iCal +- Plugin sprowadzony do JEDNEGO mechanizmu sync (zamiast 4 konkurujących) +- **Usunięte 3 pliki**: `class-sync-controller.php`, `class-gcal-service.php`, `class-oauth-handler.php` + cały katalog `integrations/google-calendar/` +- Wycięte: cała sekcja OAuth UI w Settings, handle_oauth_callback, save_gcal_credentials, notice connected/disconnected +- Wycięte per-yacht iCal: 8 metod, cron `yacht_booking_ical_import`, rewrite rule `^yacht-ical/(\d+)/...`, pola "Google Calendar ID" + "iCal Import URL" + "iCal Feed URL" w yacht-edit, kolumna w yacht-list +- Cleanup migration w `Installer::migrate()` — version-gated (idempotent), kasuje 4 stale meta keys, 6 stale options, bookings z source `ical_import`, 5 cron hooków. Bez admin notice. +- ~700+ linii martwego kodu usuniętych + +--- + +## What's In Progress + +Nic — obie pętle czysto zamknięte. Zero deferred items, zero open issues. + +--- + +## What's Next + +**Immediate:** Klient musi wykonać deploy FTP zmienionych plików (10 zmodyfikowanych + 3 usunięte). Lista w `.paul/changelog/2026-05-06.md`. Po deploy: +1. Aktywacja pluginu (lub deactivate→activate jeśli już aktywny) — wyzwoli `Installer::migrate()` → cleanup +2. Settings → Google Calendar → "Globalna synchronizacja iCal" → wkleić iCal URL Google Calendar admina → "Importuj teraz" +3. Subscribe global Export URL w Google Calendar (Inne kalendarze → Z URL-a) +4. Format eventów w GCal: `"NazwaJachtu - opis"` (np. "Maja - Kowalski 5 osób") + +**After that:** Zaplanować 09-04 (Security audit) lub 09-05 (Testy + tłumaczenia + dokumentacja). 09-04 powinien iść przed 09-05. + +--- + +## Key Files + +| File | Purpose | +|------|---------| +| `.paul/STATE.md` | Live project state | +| `.paul/ROADMAP.md` | Phase overview (5 planów w fazie 9, 3 ukończone) | +| `.paul/phases/09-finalizacja/09-02-SUMMARY.md` | Globalna iCal sync — szczegóły implementacji | +| `.paul/phases/09-finalizacja/09-03-SUMMARY.md` | Cleanup — co usunięto i czego nie ruszono | +| `.paul/changelog/2026-05-06.md` | Lista WSZYSTKICH zmienionych plików dzisiaj (do FTP deploy) | +| `wp-content/plugins/yacht-booking-system/integrations/ical/class-ical-feed.php` | Globalny iCal export (output_global_ics) | +| `wp-content/plugins/yacht-booking-system/integrations/ical/class-ical-import.php` | Globalny iCal import (run_global_import + parser prefiksu) | +| `wp-content/plugins/yacht-booking-system/includes/class-installer.php` | Cleanup migration | + +--- + +## Decyzje sesji (do pamięci) + +- Klient woli iCal feedy (publiczne URL) zamiast OAuth — prostsza konfiguracja +- Identyfikacja jachtu po prefiksie `" - "` w SUMMARY eventu (case-insensitive, exact match po lowercase post_title/alias — ŻADNYCH partial) +- Eventy w GCal bez separatora lub bez dopasowania → ignorowane (nie blokują) +- Migration "po cichu" — bez admin notice +- Per-yacht bookings z source `ical_import` USUWANE w migration (klient ponownie zaimportuje), nie migrowane do `ical_import_global` + +--- + +## Outstanding considerations + +- Jeśli klient w przyszłości będzie miał problem z dopasowaniem (długie nazwy jachtów, kolizje prefiksów) — używać pola **"Alias dla Google Calendar"** w yacht-edit +- Plugin jest gotowy produkcyjnie w warstwie integracji GCal. Pozostaje 09-04 (security) i 09-05 (testy/i18n/docs) do v1.0 release. + +--- + +## Resume Instructions + +1. Przeczytaj `.paul/STATE.md` (najnowsza pozycja) +2. Sprawdź `.paul/HANDOFF-2026-05-06.md` (ten plik) +3. Uruchom `/paul:resume` lub `/paul:progress` +4. Najprawdopodobniej: `/paul:plan` dla 09-04 (Security audit) + +--- + +*Handoff created: 2026-05-06* diff --git a/.paul/ROADMAP.md b/.paul/ROADMAP.md index 018b675..5120d7e 100644 --- a/.paul/ROADMAP.md +++ b/.paul/ROADMAP.md @@ -45,9 +45,10 @@ Szczegóły w `wp-content/plugins/yacht-booking-system/PROJECT-STATUS.md`. **Plans:** - [ ] 09-01: UX/UI polish kalendarza — half-day na pierwszym/ostatnim dniu rezerwacji + paleta widgetu pasująca do strony -- [ ] 09-02: Settings Page — uzupełnienie brakujących opcji -- [ ] 09-03: Security audit i poprawki -- [ ] 09-04: Testy + tłumaczenia + dokumentacja +- [x] 09-02: Globalna synchronizacja iCal — wspólny Google Calendar z podziałem na jachty po prefiksie nazwy w tytule eventu (export feed + import URL + alias jachtu) ✅ 2026-05-06 +- [x] 09-03: Cleanup OAuth + per-yacht iCal — usunięcie martwego kodu (3 pliki GCal/OAuth, per-yacht feedy, pole "Google Calendar ID") + cleanup migration "po cichu" ✅ 2026-05-06 +- [ ] 09-04: Security audit i poprawki +- [ ] 09-05: Testy + tłumaczenia + dokumentacja --- *Roadmap created: 2026-05-05* diff --git a/.paul/STATE.md b/.paul/STATE.md index 07b88e9..0050f8f 100644 --- a/.paul/STATE.md +++ b/.paul/STATE.md @@ -11,20 +11,20 @@ See: .paul/PROJECT.md (updated 2026-05-05) Milestone: v1.0 Production Release (v1.0.0) Phase: 9 of 9 (Finalizacja) — In progress -Plan: 09-01 — Complete (UX/UI kalendarza) -Status: Loop closed, ready for next plan (09-02) -Last activity: 2026-05-06 — Closed loop 09-01 (skos 45°, ciemne ramki, paleta brand strony) +Plan: 09-03 — Complete (Cleanup OAuth + per-yacht iCal) +Status: Loop closed, ready for next plan (09-04) +Last activity: 2026-05-06 — Closed loop 09-03 (3 pliki OAuth usunięte, per-yacht iCal wycofany, migration po cichu) Progress: -- Milestone: [████████░░] 82% -- Phase 9: [██░░░░░░░░] 25% (1 of 4 plans complete) +- Milestone: [█████████░] 92% +- Phase 9: [██████░░░░] 60% (3 of 5 plans complete) ## Loop Position Current loop state: ``` PLAN ──▶ APPLY ──▶ UNIFY - ✓ ✓ ✓ [Loop 09-01 complete, ready for 09-02] + ✓ ✓ ✓ [Loop 09-03 complete, ready for 09-04] ``` ## Accumulated Context @@ -51,10 +51,15 @@ None. ## Session Continuity -Last session: 2026-05-06 -Stopped at: Loop 09-01 closed (UX/UI kalendarza ukończone, klient zaakceptował) -Next action: Run /paul:plan to plan 09-02 (Settings Page — uzupełnienie brakujących opcji) -Resume file: .paul/phases/09-finalizacja/09-01-SUMMARY.md +Last session: 2026-05-06 (paused — end of productive day, 2 pełne pętle zamknięte) +Stopped at: Loop 09-03 zamknięty + handoff utworzony +Next action: Run /paul:plan to plan 09-04 (Security audit). Klient wykonuje deploy FTP zmienionych plików i aktywację pluginu (cleanup migration uruchomi się automatycznie). +Resume file: .paul/HANDOFF-2026-05-06.md +Resume context: +- Faza 9: 3/5 planów ukończonych (60%), milestone v1.0 92% +- Plugin sprowadzony do jednego mechanizmu sync (globalny iCal) — kontekst w 09-02 i 09-03 SUMMARY +- Brak open issues, brak deferred items, brak blockers +- Sesja zaczęła z 09-01 zamknięte, kończy z 09-03 zamknięte (2 pełne pętle PLAN→APPLY→UNIFY w jednej sesji) --- *STATE.md — Updated after every significant action* diff --git a/.paul/changelog/2026-05-06.md b/.paul/changelog/2026-05-06.md index 736e306..7669665 100644 --- a/.paul/changelog/2026-05-06.md +++ b/.paul/changelog/2026-05-06.md @@ -10,6 +10,24 @@ - Cyfry dni `#021526` (past `#6c757d`) — przebicie globalnej reguły `body a:not([href])` - Legenda rozszerzona o 3-ci swatch „Dzień odbioru / zwrotu" z gradientem - Helper `test-add-booking.php` (token-protected, akcje add/list/remove) do smoke testu — DO USUNIĘCIA z FTP po testach +- [Phase 9, Plan 02] Globalna synchronizacja iCal — jeden wspólny Google Calendar dla całej floty z podziałem po prefiksie nazwy jachtu w tytule eventu +- Globalny iCal Export feed (`/yacht-ical-global/{token}.ics`) — wszystkie rezerwacje w jednym pliku, każdy event z prefiksem `"{nazwa_jachtu} - {klient}"`, anti-loop (pomija events z source `ical_import_global`) +- Globalny iCal Import URL — pobiera kalendarz Google admina, parser dopasowuje prefiks przed `" - "` (mb_* dla polskich znaków, case-insensitive) do `post_title` lub `_yacht_gcal_alias` (priorytet alias) +- Eventy bez separatora lub bez dopasowanego jachtu — ignorowane (logowane). Stale cleanup usuwa booking gdy event zniknął z GCal +- Cron godzinny `yacht_booking_ical_global_import` + manualny przycisk "Importuj teraz" +- Pole `_yacht_gcal_alias` w yacht-edit (krótki alias, np. "Maja" zamiast "Marina Maja Sailing 35") +- Settings UI: nowa sekcja "Globalna synchronizacja iCal" z export URL (kopiuj + regeneracja tokenu), import URL, instrukcja +- Per-yacht feedy iCal i OAuth push pozostają jako kompatybilność wsteczna (out of scope ich sprzątania) +- [Phase 9, Plan 03] Cleanup OAuth + per-yacht iCal — plugin sprowadzony do JEDNEGO mechanizmu sync (globalny iCal) +- Usunięte 3 pliki OAuth (`integrations/google-calendar/class-{sync-controller,gcal-service,oauth-handler}.php`) + cały katalog +- Wycięte z bootstrap: require + setup_cron + clear_cron Sync_Controller (yacht-booking-system.php, class-yacht-booking.php) +- Wycięte z admin: cała sekcja UI OAuth (Client ID/Secret, "Połącz", "Synchronizuj teraz", instrukcja), `handle_oauth_callback`, `save_gcal_credentials`, callback/disconnect/credentials w `process_settings_save`, notice connected/disconnected +- Wycięte per-yacht iCal: `IMPORT_SOURCE`, `run_import`, `import_for_yacht`, `get/set_import_url`, `get_existing_import_map`, `upsert_booking`, `get_last_import_time`, cron `yacht_booking_ical_import`, rewrite rule `^yacht-ical/(\d+)/...`, `output_ics`, `get_feed_token`, `regenerate_token`, `get_feed_url` +- Wycięte z yacht-edit: pola "Google Calendar ID", "iCal Import URL", "iCal Feed URL". Pozostaje tylko Alias. +- Wycięte z yacht-list-table: kolumna "Google Calendar" +- Yacht class: usunięte `get_gcal_id()`, `update_gcal_id()` +- Cleanup migration w `Installer::migrate()` — version-gated (idempotent), kasuje 4 stale meta keys, 6 stale options OAuth, bookings z source `ical_import`, 5 stale cron hooków. "Po cichu" — bez admin notice +- uninstall.php zaktualizowany o globalne iCal opcje + defensywne legacy gcal_* delete ## Zmienione pliki @@ -20,5 +38,22 @@ - `test-add-booking.php` (nowy, helper testowy) - `.paul/phases/09-finalizacja/09-01-PLAN.md` (nowy) - `.paul/phases/09-finalizacja/09-01-SUMMARY.md` (nowy) +- `.paul/phases/09-finalizacja/09-02-PLAN.md` (nowy) +- `.paul/phases/09-finalizacja/09-02-SUMMARY.md` (nowy) +- `.paul/phases/09-finalizacja/09-03-PLAN.md` (nowy) +- `.paul/phases/09-finalizacja/09-03-SUMMARY.md` (nowy) +- `wp-content/plugins/yacht-booking-system/integrations/google-calendar/class-sync-controller.php` (USUNIĘTY) +- `wp-content/plugins/yacht-booking-system/integrations/google-calendar/class-gcal-service.php` (USUNIĘTY) +- `wp-content/plugins/yacht-booking-system/integrations/google-calendar/class-oauth-handler.php` (USUNIĘTY) +- `wp-content/plugins/yacht-booking-system/yacht-booking-system.php` +- `wp-content/plugins/yacht-booking-system/includes/class-yacht-booking.php` +- `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` +- `wp-content/plugins/yacht-booking-system/admin/class-yacht-list-table.php` +- `wp-content/plugins/yacht-booking-system/uninstall.php` - `.paul/STATE.md` - `.paul/ROADMAP.md` diff --git a/.paul/governance/governance_2026-05-06.jsonl b/.paul/governance/governance_2026-05-06.jsonl index c90d340..9231b71 100644 --- a/.paul/governance/governance_2026-05-06.jsonl +++ b/.paul/governance/governance_2026-05-06.jsonl @@ -31,3 +31,89 @@ {"ts":"2026-05-05T22:15:30Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} {"ts":"2026-05-05T22:15:41Z","tool":"Bash","cmd":"mkdir -p \"C:/visual studio code/projekty/jachty3.pagedev.pl/.paul/changelog/\"\",\"description\":\"Create changelog dir\"},\"tool_response\":{\"stdout\":\"\",\"stderr\":\"\",\"interrupted\":false,\"i","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} {"ts":"2026-05-05T22:15:59Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\.paul\\\\changelog\\\\2026-05-06.md","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T20:41:23Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\.paul\\\\phases\\\\09-finalizacja\\\\09-02-PLAN.md","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T20:41:36Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T20:41:43Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T20:41:48Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\.paul\\\\ROADMAP.md","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T20:43:40Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\wp-content\\\\plugins\\\\yacht-booking-system\\\\includes\\\\class-yacht.php","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T20:43:46Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\wp-content\\\\plugins\\\\yacht-booking-system\\\\includes\\\\class-installer.php","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T20:44:05Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\wp-content\\\\plugins\\\\yacht-booking-system\\\\integrations\\\\ical\\\\class-ical-feed.php","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T20:44:14Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\wp-content\\\\plugins\\\\yacht-booking-system\\\\integrations\\\\ical\\\\class-ical-feed.php","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T20:44:37Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\wp-content\\\\plugins\\\\yacht-booking-system\\\\integrations\\\\ical\\\\class-ical-feed.php","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T20:44:43Z","tool":"Bash","cmd":"php -l \"wp-content/plugins/yacht-booking-system/integrations/ical/class-ical-feed.php\" && php -l \"wp-content/plugins/yacht-booking-system/includes/class-yacht.php\" && php -l \"wp-content/plugins/y","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T20:44:56Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\wp-content\\\\plugins\\\\yacht-booking-system\\\\integrations\\\\ical\\\\class-ical-import.php","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T20:45:02Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\wp-content\\\\plugins\\\\yacht-booking-system\\\\integrations\\\\ical\\\\class-ical-import.php","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T20:45:41Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\wp-content\\\\plugins\\\\yacht-booking-system\\\\integrations\\\\ical\\\\class-ical-import.php","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T20:45:46Z","tool":"Bash","cmd":"php -l \"wp-content/plugins/yacht-booking-system/integrations/ical/class-ical-import.php\"\",\"description\":\"PHP lint Task 2\"},\"tool_response\":{\"stdout\":\"No syntax errors detected in wp-conten","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T20:45:56Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\wp-content\\\\plugins\\\\yacht-booking-system\\\\admin\\\\views\\\\yacht-edit.php","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T20:46:08Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\wp-content\\\\plugins\\\\yacht-booking-system\\\\admin\\\\views\\\\yacht-edit.php","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T20:46:17Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\wp-content\\\\plugins\\\\yacht-booking-system\\\\admin\\\\class-admin.php","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T20:46:28Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\wp-content\\\\plugins\\\\yacht-booking-system\\\\admin\\\\class-admin.php","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T20:46:39Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\wp-content\\\\plugins\\\\yacht-booking-system\\\\admin\\\\class-admin.php","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T20:47:16Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\wp-content\\\\plugins\\\\yacht-booking-system\\\\admin\\\\class-admin.php","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T20:47:36Z","tool":"Bash","cmd":"php -l \"wp-content/plugins/yacht-booking-system/admin/class-admin.php\" && php -l \"wp-content/plugins/yacht-booking-system/admin/views/yacht-edit.php\"\",\"description\":\"PHP lint Task 3 files\"},\","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T20:47:48Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T20:47:54Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T20:51:43Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T20:51:49Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T20:53:28Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\.paul\\\\phases\\\\09-finalizacja\\\\09-02-SUMMARY.md","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T20:53:37Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T20:53:42Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T20:53:51Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T20:53:57Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\.paul\\\\ROADMAP.md","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T20:54:23Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\.paul\\\\changelog\\\\2026-05-06.md","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T20:54:32Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\.paul\\\\changelog\\\\2026-05-06.md","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T20:59:54Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\.paul\\\\phases\\\\09-finalizacja\\\\09-03-PLAN.md","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:00:04Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:00:11Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:00:18Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:00:24Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\.paul\\\\ROADMAP.md","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:01:39Z","tool":"Bash","cmd":"rm -v \"wp-content/plugins/yacht-booking-system/integrations/google-calendar/class-sync-controller.php\" \"wp-content/plugins/yacht-booking-system/integrations/google-calendar/class-gcal-service.php\"","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:01:48Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\wp-content\\\\plugins\\\\yacht-booking-system\\\\yacht-booking-system.php","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:01:55Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\wp-content\\\\plugins\\\\yacht-booking-system\\\\yacht-booking-system.php","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:02:04Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\wp-content\\\\plugins\\\\yacht-booking-system\\\\includes\\\\class-yacht-booking.php","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:02:14Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\wp-content\\\\plugins\\\\yacht-booking-system\\\\admin\\\\class-admin.php","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:02:19Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\wp-content\\\\plugins\\\\yacht-booking-system\\\\admin\\\\class-admin.php","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:02:26Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\wp-content\\\\plugins\\\\yacht-booking-system\\\\admin\\\\class-admin.php","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:02:50Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\wp-content\\\\plugins\\\\yacht-booking-system\\\\admin\\\\class-admin.php","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:03:06Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\wp-content\\\\plugins\\\\yacht-booking-system\\\\admin\\\\class-admin.php","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:03:57Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\wp-content\\\\plugins\\\\yacht-booking-system\\\\admin\\\\class-admin.php","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:04:13Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\wp-content\\\\plugins\\\\yacht-booking-system\\\\admin\\\\class-admin.php","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:04:20Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\wp-content\\\\plugins\\\\yacht-booking-system\\\\admin\\\\class-admin.php","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:04:28Z","tool":"Bash","cmd":"php -l \"wp-content/plugins/yacht-booking-system/yacht-booking-system.php\" && php -l \"wp-content/plugins/yacht-booking-system/includes/class-yacht-booking.php\" && php -l \"wp-content/plugins/yacht-","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:04:44Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\wp-content\\\\plugins\\\\yacht-booking-system\\\\integrations\\\\ical\\\\class-ical-import.php","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:05:05Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\wp-content\\\\plugins\\\\yacht-booking-system\\\\integrations\\\\ical\\\\class-ical-import.php","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:05:26Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\wp-content\\\\plugins\\\\yacht-booking-system\\\\integrations\\\\ical\\\\class-ical-import.php","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:05:34Z","tool":"Bash","cmd":"php -l \"wp-content/plugins/yacht-booking-system/integrations/ical/class-ical-import.php\"\",\"description\":\"Lint ical-import after cleanup\"},\"tool_response\":{\"stdout\":\"No syntax errors detect","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:05:58Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\wp-content\\\\plugins\\\\yacht-booking-system\\\\integrations\\\\ical\\\\class-ical-feed.php","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:06:17Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\wp-content\\\\plugins\\\\yacht-booking-system\\\\integrations\\\\ical\\\\class-ical-feed.php","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:06:24Z","tool":"Bash","cmd":"php -l \"wp-content/plugins/yacht-booking-system/integrations/ical/class-ical-feed.php\"\",\"description\":\"Lint ical-feed\"},\"tool_response\":{\"stdout\":\"No syntax errors detected in wp-content/p","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:06:43Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\wp-content\\\\plugins\\\\yacht-booking-system\\\\admin\\\\views\\\\yacht-edit.php","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:06:53Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\wp-content\\\\plugins\\\\yacht-booking-system\\\\admin\\\\views\\\\yacht-edit.php","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:07:07Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\wp-content\\\\plugins\\\\yacht-booking-system\\\\admin\\\\views\\\\yacht-edit.php","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:07:13Z","tool":"Bash","cmd":"php -l \"wp-content/plugins/yacht-booking-system/admin/views/yacht-edit.php\"\",\"description\":\"Lint yacht-edit\"},\"tool_response\":{\"stdout\":\"No syntax errors detected in wp-content/plugins/yac","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:07:21Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\wp-content\\\\plugins\\\\yacht-booking-system\\\\admin\\\\class-yacht-list-table.php","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:07:28Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\wp-content\\\\plugins\\\\yacht-booking-system\\\\admin\\\\class-yacht-list-table.php","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:07:36Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\wp-content\\\\plugins\\\\yacht-booking-system\\\\admin\\\\class-admin.php","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:07:44Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\wp-content\\\\plugins\\\\yacht-booking-system\\\\admin\\\\class-admin.php","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:07:51Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\wp-content\\\\plugins\\\\yacht-booking-system\\\\includes\\\\class-yacht.php","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:07:56Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\wp-content\\\\plugins\\\\yacht-booking-system\\\\includes\\\\class-yacht.php","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:08:05Z","tool":"Bash","cmd":"php -l \"wp-content/plugins/yacht-booking-system/admin/class-admin.php\" && php -l \"wp-content/plugins/yacht-booking-system/admin/class-yacht-list-table.php\" && php -l \"wp-content/plugins/yacht-boo","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:08:28Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\wp-content\\\\plugins\\\\yacht-booking-system\\\\includes\\\\class-installer.php","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:08:35Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\wp-content\\\\plugins\\\\yacht-booking-system\\\\includes\\\\class-installer.php","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:08:49Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\wp-content\\\\plugins\\\\yacht-booking-system\\\\includes\\\\class-installer.php","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:09:02Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\wp-content\\\\plugins\\\\yacht-booking-system\\\\uninstall.php","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:09:11Z","tool":"Bash","cmd":"php -l \"wp-content/plugins/yacht-booking-system/includes/class-installer.php\" && php -l \"wp-content/plugins/yacht-booking-system/uninstall.php\" && grep -rn \"OAuth_Handler\\\\|GCal_Service\\\\|Syn","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:09:24Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:09:31Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:10:37Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:10:46Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:12:39Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\.paul\\\\phases\\\\09-finalizacja\\\\09-03-SUMMARY.md","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:12:49Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:12:56Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:13:03Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:13:10Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\.paul\\\\ROADMAP.md","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:13:29Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\.paul\\\\changelog\\\\2026-05-06.md","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:13:41Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\.paul\\\\changelog\\\\2026-05-06.md","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:16:13Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\.paul\\\\HANDOFF-2026-05-06.md","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} +{"ts":"2026-05-06T21:16:23Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\jachty3.pagedev.pl\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/jachty3.pagedev.pl"} diff --git a/.paul/phases/09-finalizacja/09-02-PLAN.md b/.paul/phases/09-finalizacja/09-02-PLAN.md new file mode 100644 index 0000000..8ebd657 --- /dev/null +++ b/.paul/phases/09-finalizacja/09-02-PLAN.md @@ -0,0 +1,325 @@ +--- +phase: 09-finalizacja +plan: 02 +type: execute +wave: 1 +depends_on: ["09-01"] +files_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/admin/class-admin.php + - wp-content/plugins/yacht-booking-system/admin/views/settings.php + - wp-content/plugins/yacht-booking-system/includes/class-yacht.php + - wp-content/plugins/yacht-booking-system/admin/views/yacht-edit.php + - wp-content/plugins/yacht-booking-system/includes/class-installer.php +autonomous: false +delegation: off +--- + + +## Goal +Wprowadzić dwukierunkową synchronizację z **jednym wspólnym Google Calendar** (przez iCal feed) z rozróżnieniem rezerwacji per jacht po prefiksie w tytule eventu (`"{nazwa_jachtu} - {tekst}"`). Frontend kalendarz dla danego jachtu pokazuje tylko jego rezerwacje. + +## Purpose +Klient (właściciel wypożyczalni) chce zarządzać rezerwacjami wszystkich jachtów w jednym Google Calendar — jednym widokiem floty. Tworzy ręcznie eventy w GCal (np. blokady, rezerwacje telefoniczne) używając prefiksu z nazwą jachtu, a strona automatycznie przypisuje je do właściwego jachtu. Jednocześnie rezerwacje złożone przez frontend trafiają z powrotem do tego samego kalendarza w spójnym formacie. + +## Output +- Globalny iCal Export feed (jeden URL z tokenem) — zawiera rezerwacje wszystkich jachtów z prefiksem nazwy jachtu w SUMMARY +- Globalny iCal Import URL — parser dopasowuje prefiks do jachtu, importuje tylko rozpoznane eventy +- Settings page — pola dla globalnego import URL i wyświetlanie globalnego export URL +- Pole `_yacht_gcal_alias` (opcjonalny alias dla skróconej nazwy w GCal) +- Per-yacht feedy iCal pozostają sprawne (kompatybilność wsteczna) + + + +## Project Context +@.paul/PROJECT.md +@.paul/ROADMAP.md +@.paul/STATE.md +@.paul/codebase/architecture.md + +## Source Files +@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/admin/class-admin.php +@wp-content/plugins/yacht-booking-system/includes/class-yacht.php +@wp-content/plugins/yacht-booking-system/includes/class-settings.php + + +- **Mechanizm** — iCal feed (publiczny URL Google Calendar) zamiast OAuth API. Powód: klient nie chce przechodzić przez OAuth, woli dodać URL i mieć synchronizację automatyczną. + → Odpowiedź: dwukierunkowo przez iCal — import z GCal feedu + export własnego feedu (admin subskrybuje go w GCal). + +- **Identyfikacja jachtu** — po prefiksie w tytule eventu, separator `" - "`. Przykład: `"Maja - Kowalski 5 osób"`, `"Kubuś - blokada serwisowa"`. + → Odpowiedź: parser wyciąga tekst przed pierwszym `" - "`, dopasowuje case-insensitive do `post_title` jachtu lub `_yacht_gcal_alias` (jeśli ustawiony — ma priorytet). + +- **Eventy bez rozpoznanego jachtu** — ignorowane. + → Odpowiedź: jeśli prefiks nie pasuje do żadnego jachtu (lub brak separatora `" - "`), event pomijany w imporcie. Brak fallbacku na "blokuj wszystkie" — klient nie chce niespodzianek. + +- **Push do GCal** — przez ten sam globalny feed iCal (admin subskrybuje feed pluginu w GCal). + → Odpowiedź: rezerwacje ze strony pojawiają się w GCal po następnej refresh subskrypcji (Google odświeża iCal subscription co kilka godzin — limit Google'a, nie pluginu). + +- **Frontend filtrowanie** — kalendarz per jacht pokazuje tylko eventy danego jachtu. + → Odpowiedź: bez zmian w widgecie — działa już teraz przez `_booking_yacht_id`. Wystarczy że import poprawnie przypisze yacht_id. + + + + + +## AC-1: Globalny iCal Export feed +```gherkin +Given admin ma kilka rezerwacji w bazie dla różnych jachtów (np. "Maja", "Kubuś") +When admin otwiera URL `/yacht-ical-global/{token}.ics` +Then odpowiedź ma Content-Type `text/calendar` +And feed zawiera VEVENT dla każdej niezanullowanej rezerwacji wszystkich jachtów +And SUMMARY każdego eventu ma format `"{nazwa_jachtu} - {imię_klienta}"` (lub z prefiksem `[Oczekująca]` gdy status pending) +And UID jest stabilny (`booking-{id}@{domain}`) — kolejne fetche zwracają ten sam UID +``` + +## AC-2: Globalny iCal Import — dopasowanie po prefiksie +```gherkin +Given globalny iCal Import URL jest ustawiony w Settings +And kalendarz Google zawiera event "Maja - Test rezerwacja" (jacht "Maja" istnieje w bazie) +And kalendarz Google zawiera event "Nieznany - cokolwiek" (brak takiego jachtu) +And kalendarz Google zawiera event "Brak separatora" (bez " - ") +When uruchamiany jest cron `yacht_booking_ical_import` (lub manualny przycisk) +Then plugin tworzy/aktualizuje booking dla jachtu "Maja" z source `ical_import_global` +And blokuje dostępność `wp_yacht_availability` tylko dla yacht_id jachtu "Maja" +And event "Nieznany" jest pominięty (logowane jako info, brak booking) +And event "Brak separatora" jest pominięty +And kolejny przebieg (nawet bez zmian w GCal) nie tworzy duplikatów (idempotencja po UID) +``` + +## AC-3: Globalny Import — czyszczenie usuniętych eventów +```gherkin +Given event "Maja - Foo" został zaimportowany przy poprzednim cron'ie +When admin usuwa go z Google Calendar +And uruchamia się kolejny cron import +Then powiązany booking (z source `ical_import_global` i tym UID) jest usuwany +And `Availability::clear_booking_availability()` zwalnia daty +``` + +## AC-4: Alias jachtu (opcjonalny) +```gherkin +Given jacht ma `post_title="Marina Maja Sailing 35"` i `_yacht_gcal_alias="Maja"` +And event w GCal ma SUMMARY "Maja - Klient X" +When uruchamia się import +Then plugin dopasowuje event do tego jachtu po aliasie +And tworzy booking z `_booking_yacht_id` = ID tego jachtu +``` + +## AC-5: Frontend filtrowanie (regresja) +```gherkin +Given booking dla jachtu "Maja" zaimportowany przez globalny iCal +When klient otwiera stronę z widgetem `[yacht_calendar yacht_id=ID_MAJA]` +Then kalendarz pokazuje datę rezerwacji jako zablokowaną +And widget jachtu "Kubuś" NIE pokazuje tej daty jako zablokowanej +``` + +## AC-6: Settings UI +```gherkin +Given admin otwiera Settings → zakładka Google Calendar / iCal +When widzi sekcję "Globalna synchronizacja iCal" +Then widzi pole "iCal Import URL" (input type=url) — globalny URL kalendarza Google +And widzi pole tylko-do-odczytu "iCal Export URL" z linkiem `/yacht-ical-global/{token}.ics` i przyciskiem "Kopiuj" +And widzi przycisk "Wygeneruj nowy token" (regeneruje token, unieważniając poprzedni URL) +And widzi przycisk "Importuj teraz" (manual trigger run_global_import) +And w yacht-edit jest nowe pole "Alias dla Google Calendar" (placeholder: nazwa jachtu) — opcjonalne +``` + + + + + + + Task 1: Globalny iCal Export feed + alias jachtu + + wp-content/plugins/yacht-booking-system/integrations/ical/class-ical-feed.php, + wp-content/plugins/yacht-booking-system/includes/class-yacht.php, + wp-content/plugins/yacht-booking-system/includes/class-installer.php + + + 1. W `class-ical-feed.php` dodaj nową ścieżkę feed: + - rewrite rule `^yacht-ical-global/([a-zA-Z0-9]+)\.ics$` → `index.php?yacht_ical_global=1&yacht_ical_token=$matches[1]` + - query var `yacht_ical_global` + - handler `handle_global_feed_request()` weryfikuje token przez `hash_equals` względem opcji `yacht_booking_global_ical_token` + - metoda `output_global_ics()`: pobiera WSZYSTKIE bookingi (nie filtrowane po yacht), iteruje, dla każdego ustala SUMMARY = `"{nazwa_jachtu} - {imię_klienta}"` (analogicznie do istniejącego `output_ics`, ale z prefiksem nazwy jachtu z `Yacht::get_post_title( yacht_id )` zamiast tylko klienta) + - skip bookingi ze statusem `cancelled` oraz z source `ical_import_global` (nie wysyłaj z powrotem do Google tego co stamtąd przyszło — anti-loop) + - UID format: `booking-{id}@{domain}` (taki sam jak per-yacht — zachować stabilność) + - X-WR-CALNAME: `"Wszystkie jachty - " . get_bloginfo('name')` + 2. Helper `get_global_feed_token()` — generuje/zwraca token z opcji, `regenerate_global_token()` — nadpisuje token. + 3. Helper `get_global_feed_url()` — zwraca pełny URL. + 4. W `class-yacht.php` dodaj akcesory: + - `get_gcal_alias( $yacht_id )` → `get_post_meta( $yacht_id, '_yacht_gcal_alias', true )` + - `update_gcal_alias( $yacht_id, $alias )` → sanitize_text_field + update_post_meta + 5. W `class-installer.php` (jeśli wersja schematu się ewoluuje) dodaj domyślne opcje: + - `add_option( 'yacht_booking_global_ical_import_url', '' )` + - `add_option( 'yacht_booking_global_ical_token', '' )` (token generowany lazy przy pierwszym fetch URL) + - flush_rewrite_rules przy aktywacji (rewrite rule). + + Avoid: nie modyfikuj istniejących per-yacht feedów — działają jako fallback i są używane przez OTA/iCal subscribers innych systemów. + + + - `php -l class-ical-feed.php` (syntax OK) + - W przeglądarce: po zapisie pluginu i flush rewrite, URL `/yacht-ical-global/{token}.ics` zwraca .ics z eventami wszystkich jachtów, każdy z prefiksem nazwy jachtu + - `curl /yacht-ical-global/{token}.ics | grep "SUMMARY"` zawiera np. `SUMMARY:Maja - Kowalski` + - URL z błędnym tokenem zwraca 403 + + AC-1, AC-4 (część dot. aliasu — akcesory) zaspokojone + + + + Task 2: Globalny iCal Import + parser prefiksu + + wp-content/plugins/yacht-booking-system/integrations/ical/class-ical-import.php + + + 1. Dodaj stałą `const GLOBAL_IMPORT_SOURCE = 'ical_import_global';` (osobna od per-yacht `IMPORT_SOURCE = 'ical_import'`). + 2. Nowa metoda statyczna `run_global_import()`: + - Pobiera URL z `get_option( 'yacht_booking_global_ical_import_url' )` + - Jeśli pusty — return false + - `wp_remote_get` z timeout 30s + - parse_ics (re-use istniejącej metody, jest prywatna — wystawić jako protected lub wynieść do helpera; preferowane: zmienić visibility na `protected` lub utworzyć publiczną wrapping) + - Pre-fetch: lista jachtów + mapa `lowercase_name_or_alias → yacht_id`. Budowa: dla każdego jachtu klucz = `_yacht_gcal_alias` (jeśli != '') albo `post_title`, wszystko `mb_strtolower` + trim. + - Pre-fetch: `existing_global_map` — bookingi z source `GLOBAL_IMPORT_SOURCE`, mapa `uid → booking_id` (analogicznie do `get_existing_import_map` ale bez filtrowania po yacht). + - Iteracja po eventach: + a. Skip jeśli brak uid/start/end lub event w przeszłości (`strtotime($event['end']) < time()`) + b. Parse SUMMARY: `$pos = mb_strpos( $summary, ' - ' )`. Jeśli `$pos === false` → log "skip: no separator", continue. + c. `$prefix = mb_strtolower( trim( mb_substr( $summary, 0, $pos ) ) )` + d. Lookup w mapie. Jeśli brak → log "skip: yacht not found for prefix '{prefix}'", continue. + e. Wywołaj `upsert_global_booking( $yacht_id, $event, $existing_id )` (nowa metoda — jak `upsert_booking` ale z `_booking_source = GLOBAL_IMPORT_SOURCE`, `_booking_customer_name = "Google Calendar (import)"`, post_title `"GCal: {summary}"`). + f. Dodaj uid do `$seen_uids`. + - Po pętli: stale cleanup — dla każdego `$uid => $booking_id` w `$existing_global_map` którego nie ma w `$seen_uids` → `Availability::clear_booking_availability($booking_id)` + `wp_delete_post($booking_id, true)`. + - `update_option( 'yacht_booking_global_ical_last_import', current_time('mysql') )`. + - return true. + 3. Hook cron: w `register()` dodać `add_action( 'yacht_booking_ical_global_import', array( __CLASS__, 'run_global_import' ) )` i w `setup_cron()` zarejestruj hourly. + 4. Hook do uruchomienia obu importów (per-yacht + global) z jednego cron tick'a — nie zmieniać istniejącego, dodać osobny `wp_schedule_event` dla `yacht_booking_ical_global_import`. + + Avoid: + - Nie usuwać per-yacht importu (kompatybilność) + - Nie używać sztywno `strpos` po bajtach — używać `mb_*` (polskie znaki w nazwach jachtów: "Kubuś", "Maja Słoneczna") + - Nie matchować po fragmentach — tylko exact equality po lower-case (inaczej "Maja" pasuje do "Maja Słoneczna" jednocześnie) + + + - `php -l class-ical-import.php` + - Test ręczny: stworzyć w Google Calendar event "Maja - test", subskrybować feed Google iCal URL w settings, kliknąć "Importuj teraz", sprawdzić że w admin → Bookings pojawia się booking przypisany do jachtu "Maja" + - Event "FooBar - test" (brak takiego jachtu) — nie tworzy bookingu, w error log linia "skip: yacht not found" + - Event "BezSeparatora" — nie tworzy bookingu + - Drugi cron tick — brak duplikatu + - Usunięcie eventu w GCal + cron → booking zniknął, daty zwolnione w `wp_yacht_availability` + + AC-2, AC-3, AC-4 (matching po aliasie) zaspokojone + + + + Task 3: Settings UI + yacht-edit alias + admin actions + + wp-content/plugins/yacht-booking-system/admin/class-admin.php, + wp-content/plugins/yacht-booking-system/admin/views/settings.php, + wp-content/plugins/yacht-booking-system/admin/views/yacht-edit.php + + + 1. `settings.php` — dodaj sekcję "Globalna synchronizacja iCal": + - Pole `yacht_booking_global_ical_import_url` (input type=url, full width) + - Read-only display: globalny export URL (`ICal_Feed::get_global_feed_url()`) — input readonly + przycisk "Kopiuj" (JS clipboard) + - Przycisk "Wygeneruj nowy token" (form POST z nonce + action `regenerate_global_ical_token`) + - Przycisk "Importuj teraz" (form POST z nonce + action `run_global_ical_import`) + - Wyświetl `yacht_booking_global_ical_last_import` ("Ostatni import: ...") + - Krótka instrukcja: "Skopiuj Export URL i dodaj jako 'Z URL-a' w Google Calendar (Inne kalendarze → Z URL). Eventy w Google nazywaj wg wzorca: 'Nazwa jachtu - opis'. Wklej iCal URL kalendarza Google poniżej." + 2. `class-admin.php` — w `process_settings_save()` (lub equivalent) zapisz nowe pole. + 3. `class-admin.php` — `process_booking_actions()` (lub nowy `process_ical_actions()`): + - obsłuż `regenerate_global_ical_token` → `ICal_Feed::regenerate_global_token()` + `?notice=token_regenerated` redirect + - obsłuż `run_global_ical_import` → `ICal_Import::run_global_import()` + `?notice=import_done` redirect + 4. `yacht-edit.php` — dodaj wiersz tabeli "Alias dla Google Calendar": + - input text `yacht_gcal_alias`, value = `Yacht::get_gcal_alias( $yacht_id )` + - Description: "Opcjonalny krótki alias używany w tytule eventu Google Calendar (np. 'Maja' zamiast 'Marina Maja Sailing 35'). Jeśli puste — używana jest pełna nazwa jachtu." + 5. `class-admin.php::process_yacht_save()` — zapisz `yacht_gcal_alias` przez `Yacht::update_gcal_alias()`. + 6. Dodaj admin notices dla token_regenerated i import_done. + + Avoid: + - Nie usuwaj istniejących pól per-yacht ("Google Calendar ID" i "iCal Import URL") — out of scope. Klient zdecyduje w kolejnym planie czy je sprzątać. + - Nie dotykaj OAuth UI (sekcja Google Calendar OAuth zostaje bez zmian). + + + - `php -l` na każdym zmienionym pliku + - W panelu admin → Settings: nowa sekcja jest widoczna, zapis URL działa, "Wygeneruj token" zmienia URL, "Importuj teraz" wywołuje import (sprawdzalne w error log lub bookingach) + - W yacht-edit: pole alias zapisuje się i odczytuje + - Token w URL ma >=20 znaków, zmiana tokenu unieważnia stary URL (403) + + AC-6 zaspokojone, AC-4 (UI dla aliasu) zaspokojone + + + + + Dwukierunkowa synchronizacja iCal z jednym wspólnym Google Calendar: + - Globalny export feed (admin subskrybuje w GCal) + - Globalny import URL (plugin pobiera kalendarz Google) + - Identyfikacja jachtu po prefiksie "Nazwa - opis" w tytule eventu + - Frontend per-jacht pokazuje tylko swoje eventy + + + 1. Settings → skopiuj Export URL. + 2. W Google Calendar → "Inne kalendarze" → "Z URL-a" → wklej Export URL → potwierdź że pojawiają się rezerwacje wszystkich jachtów z prefiksem nazwy. + 3. W Google Calendar (głównym admina) utwórz event ręczny: tytuł "Maja - Test ręcznie", data za tydzień. + 4. Skopiuj URL iCal swojego głównego kalendarza Google (Ustawienia kalendarza → Tajny adres w formacie iCal). + 5. Wklej do Settings pluginu → "iCal Import URL". + 6. Kliknij "Importuj teraz". + 7. Sprawdź: WP Admin → Rezerwacje → pojawia się booking "GCal: Maja - Test ręcznie" przypisany do jachtu "Maja". + 8. Otwórz frontend kalendarz jachtu Maja — data zablokowana. Otwórz kalendarz innego jachtu — data wolna. + 9. Usuń event w Google → uruchom "Importuj teraz" ponownie → booking znika. + 10. Stwórz w GCal "Nieznany - test" → import → brak bookingu (sprawdź WP error log: "skip: yacht not found"). + + Wpisz "approved" gdy wszystkie 10 punktów weryfikacji przejdzie, lub opisz problemy do poprawy + + + + + + +## DO NOT CHANGE +- `class-availability.php` (logika availability stabilna) +- `class-booking.php` (CPT booking — nie ruszamy) +- `wp_yacht_availability` schema (zablokowane) +- `frontend/class-calendar-widget.php` i `frontend/class-shortcode.php` (widget renderingu — działa już per-yacht) +- `class-rest-controller.php` (REST endpointy — bez zmian) +- OAuth integration (`class-oauth-handler.php`, `class-gcal-service.php`, `class-sync-controller.php`) — out of scope tego planu, push przez OAuth zostaje na razie jak jest (drugi mechanizm; klient użyje iCal a OAuth zignoruje, lub w kolejnym planie wyłączymy) +- Per-yacht iCal feed (`output_ics`) i per-yacht import (`run_import` + `import_for_yacht`) — pozostają funkcjonalne dla kompatybilności wstecznej + +## SCOPE LIMITS +- Plan NIE usuwa pól per-yacht ("Google Calendar ID", "iCal Import URL") z yacht-edit — to decyzja na osobny plan po pozytywnej weryfikacji nowej globalnej synchronizacji +- Plan NIE wyłącza OAuth push do GCal — drugi (równoległy) mechanizm; jeśli klient nie połączy OAuth, nie jest aktywny +- Brak nowych zależności (PHP libs, npm, CDN) +- Brak zmian w bazie poza dodaniem `wp_options` keys i opcjonalnym yacht meta `_yacht_gcal_alias` +- Brak tłumaczeń .pot w tym planie (Phase 9 osobno) + + + + +Przed deklaracją ukończenia planu: +- [ ] `php -l` na wszystkich zmodyfikowanych plikach przechodzi +- [ ] Globalny export URL zwraca poprawny .ics z prefiksami nazw jachtów +- [ ] Globalny import URL parsuje eventy z GCal i przypisuje do jachtów po prefiksie +- [ ] Eventy bez separatora lub bez dopasowanego jachtu są ignorowane (logowane) +- [ ] Idempotencja: wielokrotne uruchomienie importu nie tworzy duplikatów +- [ ] Stale cleanup: usunięcie eventu w GCal + import → booking znika +- [ ] Frontend kalendarz per-jacht pokazuje tylko swoje rezerwacje (regresja) +- [ ] Per-yacht feedy iCal nadal działają (nie zostały zepsute) +- [ ] Settings UI: zapis URL, regeneracja tokenu, manual import, alias jachtu działają +- [ ] Wszystkie acceptance criteria spełnione +- [ ] Checkpoint human-verify zaakceptowany przez klienta + + + +- Klient może zarządzać rezerwacjami całej floty w jednym Google Calendar +- Eventy ręczne w GCal z prefiksem "Nazwa jachtu - ..." automatycznie pojawiają się jako blokady na frontendzie tego jachtu +- Rezerwacje ze strony pojawiają się w GCal admina (po refresh subskrypcji Google) +- Każdy frontend kalendarz pokazuje tylko swoje rezerwacje +- Zachowana kompatybilność wsteczna (per-yacht feedy + OAuth push nadal działają) + + + +Po ukończeniu utwórz `.paul/phases/09-finalizacja/09-02-SUMMARY.md` zawierający: +- Co zbudowano (export feed, import, settings UI, alias) +- Decyzje (separator " - ", lookup case-insensitive po post_title/alias, ignore unmatched) +- Otwarte pytania na kolejny plan (czy usuwać pola per-yacht? czy wyłączać OAuth push?) +- Ścieżkę testową odtworzeniową + diff --git a/.paul/phases/09-finalizacja/09-02-SUMMARY.md b/.paul/phases/09-finalizacja/09-02-SUMMARY.md new file mode 100644 index 0000000..3ccc012 --- /dev/null +++ b/.paul/phases/09-finalizacja/09-02-SUMMARY.md @@ -0,0 +1,170 @@ +--- +phase: 09-finalizacja +plan: 02 +subsystem: integrations +tags: [ical, google-calendar, sync, multi-yacht, prefix-matching] + +requires: + - phase: 04-frontend-kalendarz + provides: widget kalendarza per-yacht (już filtruje po _booking_yacht_id) + - phase: 08-gcal-synchronizacja + provides: per-yacht ICal_Feed/ICal_Import + OAuth GCal_Service (zachowane jako fallback) + +provides: + - 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" + +affects: + - 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) + +tech-stack: + added: + - mb_strtolower/mb_substr/mb_strpos do parsowania prefiksu (poprawne dla polskich znaków) + patterns: + - "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)" + +key-files: + 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 + +key-decisions: + - "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)" + +patterns-established: + - "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')" + +duration: ~25min +started: 2026-05-06T11:00:00Z +completed: 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* diff --git a/.paul/phases/09-finalizacja/09-03-PLAN.md b/.paul/phases/09-finalizacja/09-03-PLAN.md new file mode 100644 index 0000000..ab1ed80 --- /dev/null +++ b/.paul/phases/09-finalizacja/09-03-PLAN.md @@ -0,0 +1,440 @@ +--- +phase: 09-finalizacja +plan: 03 +type: execute +wave: 1 +depends_on: ["09-02"] +files_modified: + - wp-content/plugins/yacht-booking-system/yacht-booking-system.php + - wp-content/plugins/yacht-booking-system/includes/class-yacht-booking.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 + - wp-content/plugins/yacht-booking-system/admin/class-yacht-list-table.php + - wp-content/plugins/yacht-booking-system/integrations/ical/class-ical-import.php + - wp-content/plugins/yacht-booking-system/integrations/ical/class-ical-feed.php + - wp-content/plugins/yacht-booking-system/uninstall.php +files_deleted: + - wp-content/plugins/yacht-booking-system/integrations/google-calendar/class-sync-controller.php + - wp-content/plugins/yacht-booking-system/integrations/google-calendar/class-gcal-service.php + - wp-content/plugins/yacht-booking-system/integrations/google-calendar/class-oauth-handler.php +autonomous: false +delegation: off +--- + + +## Goal +Posprzątać po globalnej iCal sync: usunąć martwe i zbędne mechanizmy (OAuth push do GCal, per-jacht iCal import URL, per-jacht feed, pole "Google Calendar ID"). Pozostawić tylko jeden mechanizm — globalny iCal feed (export + import) wprowadzony w 09-02. + +## Purpose +Po 09-02 plugin ma DWA równoległe mechanizmy synchronizacji z GCal: globalny iCal (używany przez klienta) i OAuth push (uśpiony, klient nie używa) + per-yacht iCal feedy/importy (relikt sprzed globalnego). To komplikuje model mentalny i potencjalnie powoduje duplikaty. Sprzątanie eliminuje confusing UI i tysiące linii martwego kodu, czyniąc plugin gotowym produkcyjnie do v1.0. + +## Output +- Usunięte 3 pliki OAuth/GCal (`class-sync-controller.php`, `class-gcal-service.php`, `class-oauth-handler.php`) +- Wyłączony cały OAuth flow (UI w settings, hooki cron, callback redirect, AJAX manual sync) +- Usunięty per-jacht iCal feed (`output_ics`, `get_feed_token`, rewrite rule `^yacht-ical/(\d+)/...`) +- Usunięty per-jacht iCal import (cron `yacht_booking_ical_import`, `run_import`, `import_for_yacht`, pole `iCal Import URL` w yacht-edit, kolumna w yacht-list) +- Usunięte pole "Google Calendar ID" w yacht-edit + metody `Yacht::get_gcal_id`/`update_gcal_id` +- Cleanup migration: jednorazowy `delete_post_meta` (_yacht_gcal_id, _yacht_ical_import_url, _yacht_ical_token, _yacht_ical_last_import) + `delete_option` (gcal_*, gcal credentials, gcal_sync_enabled) +- Zaktualizowany `uninstall.php` + + + +## Project Context +@.paul/PROJECT.md +@.paul/ROADMAP.md +@.paul/STATE.md +@.paul/codebase/architecture.md +@.paul/phases/09-finalizacja/09-02-SUMMARY.md + +## Source Files +@wp-content/plugins/yacht-booking-system/yacht-booking-system.php +@wp-content/plugins/yacht-booking-system/includes/class-yacht-booking.php +@wp-content/plugins/yacht-booking-system/admin/class-admin.php +@wp-content/plugins/yacht-booking-system/integrations/ical/class-ical-import.php +@wp-content/plugins/yacht-booking-system/integrations/ical/class-ical-feed.php +@wp-content/plugins/yacht-booking-system/integrations/google-calendar/class-sync-controller.php +@wp-content/plugins/yacht-booking-system/integrations/google-calendar/class-gcal-service.php +@wp-content/plugins/yacht-booking-system/integrations/google-calendar/class-oauth-handler.php + + +- **GCal ID per-jacht** — Usunąć z UI + skasować meta z bazy. + → Odpowiedź: pole `_yacht_gcal_id` było martwe (OAuth używał globalnej opcji). Usuwamy pole z yacht-edit, metody `Yacht::get_gcal_id`/`update_gcal_id`, kolumnę z yacht-list-table, oraz wywołujemy `delete_post_meta` w cleanup migration. + +- **Per-jacht iCal Import URL** — Usunąć całkowicie (UI + cron + dane). + → Odpowiedź: usuwamy pole `iCal Import URL` z yacht-edit, kolumnę z yacht-list, hook `yacht_booking_ical_import`, metody `run_import`, `import_for_yacht`, `get_import_url`, `set_import_url`, `get_last_import_time`, `get_existing_import_map`, `upsert_booking` (per-yacht), stałą `IMPORT_SOURCE`. Per-yacht booking source `ical_import` zostaje rozpoznany w cleanup migration jako kandydat do usunięcia (rozważymy w boundaries — patrz niżej). + +- **OAuth push do GCal** — Wyłączyć całkowicie i usunąć. + → Odpowiedź: usuwamy 3 pliki (`class-sync-controller.php`, `class-gcal-service.php`, `class-oauth-handler.php`), wszystkie hooki w bootstrap, sekcję UI OAuth w `render_google_calendar_settings`, AJAX `wp_ajax_yacht_booking_manual_sync`, ścieżkę OAuth callback w `process_settings_save`, notice connected/disconnected. Sekcja Settings → Google Calendar zawiera już teraz TYLKO globalną iCal sync. + +- **Migracja** — Bez widocznej migracji, po cichu. + → Odpowiedź: cleanup wykonuje się w `Installer::install()` przy aktywacji nowej wersji (sprawdzamy zapisaną wersję pluginu vs `YACHT_BOOKING_VERSION` — jeśli upgrade z wersji + + + + +## AC-1: Pliki OAuth/Sync usunięte i nie ładowane +```gherkin +Given plugin po nowym deploy +When sprawdzamy strukturę katalogu integrations/ +Then nie istnieje plik class-sync-controller.php +And nie istnieje plik class-gcal-service.php +And nie istnieje plik class-oauth-handler.php +And bootstrap pluginu (yacht-booking-system.php + class-yacht-booking.php) nie odwołuje się do żadnej z tych klas +And `php -l` na bootstrap nie zgłasza błędów +And aktywacja pluginu w WP Admin nie powoduje fatal error +``` + +## AC-2: Sekcja OAuth zniknęła z Settings, globalna iCal pozostała +```gherkin +Given admin otwiera WP Admin → Rezerwacje Jachtów → Ustawienia → zakładka Google Calendar +When strona się renderuje +Then NIE widzi "Krok 1: Dodaj dane OAuth" +And NIE widzi "Krok 2: Autoryzuj połączenie" +And NIE widzi przycisku "Synchronizuj teraz" (AJAX manual sync) +And NIE widzi pola "Client ID"/"Client Secret" +And widzi sekcję "Globalna synchronizacja iCal" (z 09-02) z polami import URL + export URL +And działa "Importuj teraz" + zapis URL + regeneracja tokenu +``` + +## AC-3: Pola per-jacht zniknęły z yacht-edit i yacht-list +```gherkin +Given admin otwiera Edycję jachtu (yacht-bookings-add-yacht) +When strona się renderuje +Then NIE widzi pola "Google Calendar ID" +And NIE widzi pola "iCal Import URL" +And NIE widzi linku "iCal Feed URL" per-jacht +And widzi nadal pole "Alias dla Google Calendar" (z 09-02 — to jest aktywne dla globalnego importu) +And lista jachtów (yacht-bookings) NIE pokazuje kolumny GCal ID ani iCal status +``` + +## AC-4: Per-jacht iCal cron i feed wyłączone +```gherkin +Given plugin po deploy nowej wersji +When sprawdzamy zarejestrowane crony WP +Then NIE jest zaplanowany hook 'yacht_booking_ical_import' (per-yacht) +And NIE jest zaplanowany hook 'yacht_booking_pull_from_gcal' (OAuth pull) +And NIE jest zaplanowany hook 'yacht_booking_sync_to_gcal' (OAuth push) +And JEST zaplanowany hook 'yacht_booking_ical_global_import' (z 09-02) +And URL `/yacht-ical/{yacht_id}/{token}.ics` zwraca 404 (per-yacht feed niedostępny) +And URL `/yacht-ical-global/{token}.ics` nadal działa (z 09-02) +``` + +## AC-5: Cleanup migration — czysta baza +```gherkin +Given baza ma stare meta (_yacht_gcal_id, _yacht_ical_import_url, _yacht_ical_token, _yacht_ical_last_import) +And baza ma stare opcje (yacht_booking_gcal_calendar_id, yacht_booking_gcal_credentials, yacht_booking_gcal_oauth_*, yacht_booking_gcal_sync_enabled) +And baza ma rezerwacje z _booking_source = 'ical_import' (per-yacht) +When admin aktywuje nową wersję pluginu (lub uruchomi się hook upgrade) +Then wszystkie wymienione meta są usunięte (delete_post_meta) +And wszystkie wymienione opcje są usunięte (delete_option) +And rezerwacje z source 'ical_import' są usunięte (Availability::clear_booking_availability + wp_delete_post) +And opcja `yacht_booking_version` ma nową wartość pluginu +And cleanup wykonuje się TYLKO RAZ (kolejna aktywacja nie powtarza) +``` + +## AC-6: Globalna iCal sync (z 09-02) działa bez regresji +```gherkin +Given po cleanup admin ma globalny iCal Import URL ustawiony +When kliknie "Importuj teraz" +Then plugin pobiera kalendarz Google +And eventy z prefiksem nazwy jachtu są importowane jako rezerwacje (source 'ical_import_global') +And frontend kalendarz per-jacht pokazuje tylko swoje rezerwacje +And export feed `/yacht-ical-global/{token}.ics` zwraca poprawny .ics +``` + +## AC-7: uninstall.php zaktualizowany +```gherkin +Given admin usuwa plugin przez Plugins → Delete +When uruchamia się uninstall.php +Then NIE próbuje delete_option dla nieistniejących już kluczy (lub robi to bezpiecznie — delete_option jest no-op dla nieistniejących) +And usuwa wszystkie aktualne klucze: yacht_booking_global_ical_*, yacht_booking_default_status, yacht_booking_email_*, etc. +And usuwa wszystkie meta jachtów + bookingów + tabele wp_yacht_availability (jak dotąd) +``` + + + + + + + Task 1: Usunąć OAuth/Sync/GCal_Service — pliki i wszystkie odniesienia + + wp-content/plugins/yacht-booking-system/integrations/google-calendar/class-sync-controller.php (DELETE), + wp-content/plugins/yacht-booking-system/integrations/google-calendar/class-gcal-service.php (DELETE), + wp-content/plugins/yacht-booking-system/integrations/google-calendar/class-oauth-handler.php (DELETE), + wp-content/plugins/yacht-booking-system/yacht-booking-system.php, + wp-content/plugins/yacht-booking-system/includes/class-yacht-booking.php, + wp-content/plugins/yacht-booking-system/admin/class-admin.php + + + 1. **Usunąć 3 pliki** w `integrations/google-calendar/`: + - `class-sync-controller.php` + - `class-gcal-service.php` + - `class-oauth-handler.php` + Można usunąć cały katalog `integrations/google-calendar/` jeśli to jedyne pliki (sprawdź `ls integrations/google-calendar/` przed delete). + + 2. **`yacht-booking-system.php` (bootstrap)**: + - Usunąć `require_once` dla 3 plików GCal (jeśli są) + - Usunąć wywołania `Sync_Controller::get_instance()`, `Sync_Controller::register_cron_actions()`, `Sync_Controller::setup_cron()`, `Sync_Controller::clear_cron()` w hookach activate/deactivate/plugins_loaded + - Zachować bez zmian wszystkie wywołania ICal_* (te zostają) + + 3. **`includes/class-yacht-booking.php`**: + - W metodzie `init()` lub `register()` usunąć linie tworzące/inicjalizujące `Sync_Controller`, `GCal_Service`, `OAuth_Handler` + - Usunąć `require_once` dla 3 plików GCal + + 4. **`admin/class-admin.php` — masywny refactor sekcji OAuth**: + - W `process_settings_save()`: + - Usunąć `require_once` dla `class-oauth-handler.php` i `class-gcal-service.php` + - Usunąć blok obsługujący `gcal_callback` (OAuth callback redirect) + - Usunąć blok `yacht_booking_disconnect_gcal` + - Usunąć blok `yacht_booking_save_gcal_credentials` + - **ZACHOWAĆ** bloki: globalny iCal save, regenerate token, run global import, save_settings (general), save_email_templates + - Usunąć metodę `handle_oauth_callback()` + - Usunąć metodę `save_gcal_credentials()` + - W `display_admin_notices()`: usunąć notice `connected`, `disconnected`. Pozostawić: saved, templates_saved, templates_reset, error, global_ical_saved, token_regenerated, global_import_done, global_import_failed + - W `render_google_calendar_settings()`: usunąć CAŁĄ sekcję `if ( ! $is_connected ) ... else ... endif` (Step 1: credentials, Step 2: authorize, Connected status, Manual sync, Instrukcja). **ZACHOWAĆ** sekcję "Globalna synchronizacja iCal" (z 09-02). Metoda po refactorze powinna mieć tylko: nagłówek `

` + tę jedną sekcję `
` z 09-02. + - Usunąć lokalne require_once `OAuth_Handler` i `GCal_Service` w tej metodzie (już niepotrzebne). + - Pozostawić bez zmian `process_yacht_save`, `save_yacht`, list table'y, eksport CSV, etc. + + Avoid: + - Nie ruszać sekcji "Globalna synchronizacja iCal" (z 09-02) — to jest TO co zostaje + - Nie usuwać CSS/JS dla globalnego iCal + - Nie usuwać AJAX handler globalnego iCal (jeśli istnieje — w 09-02 jest tylko form POST, żaden AJAX) + + + - `ls integrations/google-calendar/` zwraca pustkę lub katalog nie istnieje + - `grep -r "OAuth_Handler\|GCal_Service\|Sync_Controller\|GoogleCalendar" wp-content/plugins/yacht-booking-system --include="*.php"` zwraca 0 wyników (poza komentarzami w summary/changelog) + - `php -l` przechodzi na: yacht-booking-system.php, class-yacht-booking.php, class-admin.php + - W WP Admin → Settings → Google Calendar widać TYLKO sekcję "Globalna synchronizacja iCal" + - Brak fatal error przy aktywacji (sprawdź `?WP_DEBUG=true` lub error log) + + AC-1 i część AC-2 satisfied (sekcja OAuth zniknęła) + + + + Task 2: Usunąć per-jacht iCal feed/import + pole gcal_id z UI + + wp-content/plugins/yacht-booking-system/integrations/ical/class-ical-import.php, + wp-content/plugins/yacht-booking-system/integrations/ical/class-ical-feed.php, + wp-content/plugins/yacht-booking-system/admin/views/yacht-edit.php, + wp-content/plugins/yacht-booking-system/admin/class-yacht-list-table.php, + wp-content/plugins/yacht-booking-system/admin/class-admin.php, + wp-content/plugins/yacht-booking-system/includes/class-yacht.php + + + 1. **`class-ical-import.php` — usuwamy mechanizm per-yacht, zostaje tylko globalny**: + - Usunąć stałą `IMPORT_SOURCE` (zachować `GLOBAL_IMPORT_SOURCE` i `SUMMARY_SEPARATOR`) + - W `register()`: usunąć `add_action( 'yacht_booking_ical_import', ... )` (zostaje tylko `yacht_booking_ical_global_import`) + - W `setup_cron()`: usunąć `wp_schedule_event` dla `yacht_booking_ical_import` + - W `clear_cron()`: usunąć `wp_clear_scheduled_hook( 'yacht_booking_ical_import' )` + - Usunąć metody publiczne: `run_import()`, `get_import_url()`, `set_import_url()`, `get_last_import_time()` + - Usunąć metody prywatne: `import_for_yacht()`, `get_existing_import_map()`, `upsert_booking()` (per-yacht — zachować `upsert_global_booking`!) + - Zachować: `parse_ics`, helpers (`line_starts_with`, `extract_value`, `parse_ical_date`, `unescape_ical`), `log`, oraz cały globalny mechanizm (run_global_import, build_yacht_lookup_map, match_yacht_by_prefix, get_existing_global_import_map, upsert_global_booking) + + 2. **`class-ical-feed.php` — usuwamy per-yacht feed, zostaje tylko globalny**: + - W `add_rewrite_rules()`: usunąć rule `^yacht-ical/([0-9]+)/([a-zA-Z0-9]+)\.ics$` (zostaje tylko global). Zaktualizować flush check. + - W `add_query_vars()`: usunąć `yacht_ical_id` (zostają `yacht_ical_token` i `yacht_ical_global`) + - W `handle_feed_request()`: usunąć cały blok per-yacht (zachować tylko branch global) + - Usunąć metody: `get_feed_token()`, `regenerate_token()`, `get_feed_url()`, `output_ics()` + - Zachować: `register()`, `add_rewrite_rules()` (już poprawiony), `add_query_vars()` (poprawiony), `handle_feed_request()` (poprawiony), wszystkie metody global, `escape_ical()` + + 3. **`admin/views/yacht-edit.php`**: + - Usunąć całe wiersze tabeli z polami: `yacht_gcal_id`, `yacht_ical_import_url`, oraz blok wyświetlający per-yacht iCal Feed URL (z tokenem) + - Usunąć z PHP na górze pliku: `$gcal_id = ...`, `$ical_import_url = ...`, `$ical_feed_url = ...`, `$ical_last_import = ...` + - **ZACHOWAĆ** pole `yacht_gcal_alias` (z 09-02 — używane przez globalny import) + - Pozostawić bez zmian: title, description, capacity, price_per_day, features + + 4. **`admin/class-yacht-list-table.php`**: + - Usunąć z `get_columns()` kolumnę dla GCal i iCal status (jeśli istnieją) + - Usunąć metodę `column_gcal_id()` lub equivalent (linia ok. 173 — `Yacht::get_gcal_id`) + - Sprawdź czy są inne kolumny używające usuniętych meta — usuń ich rendering + + 5. **`admin/class-admin.php` — czyszczenie save_yacht**: + - W `save_yacht()`: usunąć linie: + - `$gcal_id = ...` + - `Yacht::update_gcal_id( $saved_id, $gcal_id );` + - `$ical_import_url = ...` + - `\YachtBooking\Integrations\ICal\ICal_Import::set_import_url( ... )` + - **ZACHOWAĆ** zapis aliasu (`Yacht::update_gcal_alias`) + + 6. **`includes/class-yacht.php`**: + - Usunąć metody: `get_gcal_id()`, `update_gcal_id()` + - **ZACHOWAĆ**: get_capacity, update_capacity, get_price_per_day, update_price_per_day, get_features, update_features, get_gcal_alias, update_gcal_alias + + Avoid: + - Nie tknąć w żaden sposób mechanizmu globalnego iCal (run_global_import, output_global_ics, alias) + - Nie usuwać cron `yacht_booking_ical_global_import` (z 09-02) + - Nie usuwać `parse_ics` ani helperów iCal — używane przez globalny import + + + - `php -l` przechodzi na: class-ical-import.php, class-ical-feed.php, yacht-edit.php, class-yacht-list-table.php, class-admin.php, class-yacht.php + - `grep -r "yacht_booking_ical_import\|run_import\|import_for_yacht\|get_gcal_id\|update_gcal_id\|_yacht_gcal_id\|_yacht_ical_import_url" wp-content/plugins/yacht-booking-system --include="*.php"` zwraca 0 wyników (lub tylko komentarze) + - W WP Admin → Edycja jachtu: NIE widać pól "Google Calendar ID", "iCal Import URL", "iCal Feed URL". WIDAĆ pole "Alias dla Google Calendar". + - URL `/yacht-ical/824/jakistoken.ics` zwraca 404 + - URL `/yacht-ical-global/{token}.ics` nadal działa + + AC-3, AC-4, część AC-2 (UI per-yacht) satisfied + + + + Task 3: Cleanup migration w Installer + uninstall.php + + wp-content/plugins/yacht-booking-system/includes/class-installer.php, + wp-content/plugins/yacht-booking-system/uninstall.php + + + 1. **`class-installer.php` — dodać metodę `migrate()` wywoływaną z `install()`**: + - Logika: pobierz `yacht_booking_version` z opcji. Jeśli istnieje i jest niższa niż `YACHT_BOOKING_VERSION` (czyli to upgrade) — uruchom cleanup. + - Cleanup operacje: + a. **Delete post meta** dla wszystkich jachtów: + - `_yacht_gcal_id` + - `_yacht_ical_import_url` + - `_yacht_ical_token` + - `_yacht_ical_last_import` + Sposób: `delete_post_meta_by_key( '_yacht_gcal_id' )` (WordPress core function — usuwa meta dla wszystkich postów). Powtórzyć dla każdego klucza. + b. **Delete options** (OAuth/credentials): + - `yacht_booking_gcal_calendar_id` + - `yacht_booking_gcal_credentials` + - `yacht_booking_gcal_oauth_access_token` + - `yacht_booking_gcal_oauth_refresh_token` + - `yacht_booking_gcal_oauth_token_expires` + - `yacht_booking_gcal_oauth_email` + - `yacht_booking_gcal_sync_enabled` + (sprawdź faktyczne nazwy w `class-oauth-handler.php` ZANIM zostanie usunięty w Task 1 — albo grep bashem PRZED. Lista powyżej to typowe; jeśli różne nazwy, skoryguj) + c. **Delete bookings** z `_booking_source = 'ical_import'` (per-yacht): + ```php + $bookings = get_posts( array( + 'post_type' => 'yacht_booking', + 'posts_per_page' => -1, + 'fields' => 'ids', + 'meta_query' => array( + array( 'key' => '_booking_source', 'value' => 'ical_import' ), + ), + ) ); + foreach ( $bookings as $booking_id ) { + Availability::clear_booking_availability( $booking_id ); + wp_delete_post( $booking_id, true ); + } + ``` + d. **Clear stale crons**: `wp_clear_scheduled_hook( 'yacht_booking_ical_import' )`, `wp_clear_scheduled_hook( 'yacht_booking_pull_from_gcal' )`, `wp_clear_scheduled_hook( 'yacht_booking_sync_to_gcal' )`, `wp_clear_scheduled_hook( 'yacht_booking_update_in_gcal' )`, `wp_clear_scheduled_hook( 'yacht_booking_delete_from_gcal' )`. + - Idempotencja: `set_version()` w `install()` ZAWSZE nadpisuje `yacht_booking_version` aktualną wartością → przy kolejnej aktywacji warunek `version < CURRENT` jest fałszem → migrate() nic nie robi. ✓ + - Wywołać `migrate()` w `install()` PRZED `set_version()`. + + 2. **`uninstall.php`**: + - Sprawdź obecną zawartość (`Read`). + - Usuń `delete_option` dla nieistniejących już kluczy GCal (te z punktu 1.b) + - **ZACHOWAJ** delete_option dla: + - `yacht_booking_default_status`, `yacht_booking_email_from_name`, `yacht_booking_email_from`, `yacht_booking_date_format`, `yacht_booking_currency_symbol`, `yacht_booking_terms_page_id`, `yacht_booking_enable_notifications` + - `yacht_booking_global_ical_import_url`, `yacht_booking_global_ical_token`, `yacht_booking_global_ical_last_import` + - `yacht_booking_email_templates`, `yacht_booking_version`, `yacht_booking_installed_at`, `yacht_booking_enabled` + - **ZACHOWAJ** delete `wp_yacht_availability` table + delete_post_meta dla wszystkich CPT meta + wp_delete_post dla CPT. + + Avoid: + - Nie usuwać `_yacht_gcal_alias` (aktywny dla globalnego importu) + - Nie usuwać `_booking_source = 'ical_import_global'` (aktywne globalne importy z 09-02 — zostawić!) + - Nie usuwać innych user data (rezerwacji ze strony — `_booking_source != 'ical_import'`) + - Cleanup ma być idempotentny — uruchamia się TYLKO przy upgrade z wersji < CURRENT + + + - `php -l` przechodzi na: class-installer.php, uninstall.php + - Symulacja upgrade: ustaw `yacht_booking_version` na '0.9.0' w bazie testowej (lub starsza), aktywuj plugin → cleanup wykonuje się; wszystkie wymienione meta i opcje zniknęły; rezerwacje ze starym source 'ical_import' usunięte; rezerwacje globalne ('ical_import_global') i ze strony pozostały + - Po cleanup: `wp_options` nie zawiera kluczy gcal_oauth_*, gcal_credentials, gcal_calendar_id, gcal_sync_enabled + - Druga aktywacja po pierwszej → migrate() nic nie robi (cicha) + + AC-5, AC-7 satisfied + + + + + Posprzątany plugin: jeden mechanizm sync (globalny iCal), zero martwych pól, czysta baza po upgrade. + - Usunięte 3 pliki OAuth/Sync/GCal_Service + - Usunięty per-jacht iCal feed (URL `/yacht-ical/{id}/...` zwraca 404) + - Usunięty per-jacht iCal import (cron i pole) + - Usunięte pole "Google Calendar ID" z yacht-edit + - Cleanup migration: stare meta, opcje OAuth, rezerwacje per-yacht 'ical_import' → wyczyszczone + - Settings → Google Calendar zawiera TYLKO sekcję "Globalna synchronizacja iCal" + + + 1. Po deploy FTP wejdź do WP Admin (jeśli plugin nieaktywny — aktywuj). To wyzwoli `Installer::install()` z migracją. + 2. Sprawdź WP Admin → Rezerwacje Jachtów → Ustawienia → Google Calendar: + - **NIE ma** sekcji OAuth (Client ID, "Połącz z Google Calendar", "Synchronizuj teraz") + - **JEST** sekcja "Globalna synchronizacja iCal" z 09-02 (export URL, import URL, "Importuj teraz") + 3. Wejdź w edycję dowolnego jachtu (np. yacht_id=824): + - **NIE ma** pól "Google Calendar ID", "iCal Import URL", "iCal Feed URL" + - **JEST** pole "Alias dla Google Calendar" + 4. Sprawdź listę jachtów (Rezerwacje Jachtów → Wszystkie Jachty): + - **Nie ma** kolumn związanych z GCal/iCal per-jacht + 5. Otwórz w przeglądarce dowolny stary URL per-yacht: `https://jachty3.pagedev.pl/yacht-ical/824/jakikolwiek_token.ics` → **404 Not Found** + 6. Otwórz globalny URL z Settings (Krok 1) → **zwraca .ics z rezerwacjami** + 7. Settings → "Importuj teraz" → komunikat sukcesu, w error log nie ma fatal error + 8. Sprawdź bazę (phpMyAdmin lub WP-CLI): + - `SELECT * FROM wp_postmeta WHERE meta_key IN ('_yacht_gcal_id','_yacht_ical_import_url','_yacht_ical_token','_yacht_ical_last_import')` → 0 wierszy + - `SELECT * FROM wp_options WHERE option_name LIKE 'yacht_booking_gcal_%'` → 0 wierszy + - `SELECT post_id FROM wp_postmeta WHERE meta_key='_booking_source' AND meta_value='ical_import'` → 0 wierszy + - `SELECT option_value FROM wp_options WHERE option_name='yacht_booking_global_ical_token'` → JEST (zachowane) + 9. Frontend: otwórz stronę z kalendarzem dowolnego jachtu → kalendarz się ładuje, dostępność pokazuje (test regresji widget) + 10. Złóż testową rezerwację na frontendzie → trafia do bazy, pojawia się w admin → po refresh GCal subscription pojawi się w globalnym kalendarzu Google admina + + Wpisz "approved" gdy 10 punktów przejdzie, lub opisz problemy do naprawy + + + + + + +## DO NOT CHANGE +- **Globalna synchronizacja iCal (09-02)** — `output_global_ics`, `run_global_import`, `build_yacht_lookup_map`, `match_yacht_by_prefix`, `upsert_global_booking`, settings UI sekcja "Globalna synchronizacja iCal", `_yacht_gcal_alias`, opcje `yacht_booking_global_ical_*`, cron `yacht_booking_ical_global_import` +- **`Yacht::get_gcal_alias`/`update_gcal_alias`** — używane przez globalny import +- **CPT yacht_booking i yacht** — schemat, capabilities, registration +- **`wp_yacht_availability`** — tabela i logika `Availability` +- **Frontend widget i shortcode** — działają dzięki `_booking_yacht_id` +- **REST API** (`Rest_Controller`) — endpoint POST /bookings używa wewnętrznych funkcji booking::create, niezależny od GCal +- **Email templates + Inquiry CPT + CSV export** — out of scope + +## SCOPE LIMITS +- Plan NIE dotyka security audit (to 09-04) +- Plan NIE dotyka tłumaczeń .pot/.po/.mo (to 09-05) +- Plan NIE refactoruje `parse_ics` ani helperów iCal (działają — zostają) +- Plan NIE zmienia formatu prefiksu w SUMMARY (separator `" - "` z 09-02 zostaje) +- Brak nowych dependencies +- Brak admin notice o migracji (klient wybrał "po cichu") +- Plan NIE migruje rezerwacji typu 'ical_import' do 'ical_import_global' — usuwa je (klient ponownie zaimportuje przez globalny mechanizm) + + + + +Przed deklaracją ukończenia planu: +- [ ] `php -l` przechodzi na wszystkich zmodyfikowanych plikach +- [ ] `grep -r "OAuth_Handler\|GCal_Service\|Sync_Controller"` w plugin dir → 0 wyników (poza logami/changelog) +- [ ] `grep -r "yacht_booking_ical_import[^_]"` (bez `_global`) → 0 wyników +- [ ] `grep -r "_yacht_gcal_id\|_yacht_ical_import_url\|_yacht_ical_token"` → 0 wyników w runtime code +- [ ] Aktywacja pluginu w WP nie powoduje fatal error (sprawdź error log) +- [ ] Cleanup migration wykonuje się raz (przy upgrade) i jest idempotentne +- [ ] Globalna iCal sync działa bez regresji (export + import + frontend) +- [ ] URL per-yacht feed zwraca 404 +- [ ] uninstall.php usuwa wszystkie aktualne klucze (nic więcej, nic mniej) +- [ ] Wszystkie 7 acceptance criteria spełnione +- [ ] Checkpoint human-verify zaakceptowany przez klienta + + + +- Plugin ma JEDEN mechanizm synchronizacji z GCal: globalny iCal feed (eksport + import) +- Zero martwego kodu (3 pliki usunięte, ~500+ linii zbędnego UI/cron usuniętych) +- Czysta baza po upgrade (klient nie widzi starych pól, baza nie zawiera nieaktywnych meta/opcji) +- Brak regresji w globalnej iCal sync ani frontendzie +- Plugin gotowy produkcyjnie w warstwie integracji GCal (pozostaje security audit + i18n + docs) + + + +Po ukończeniu utwórz `.paul/phases/09-finalizacja/09-03-SUMMARY.md` zawierający: +- Co usunięto (lista plików + linii kodu jeśli istotna) +- Co zachowano (globalna iCal sync, alias, frontend) +- Wyniki cleanup migration (ile meta/opcji/rezerwacji zostało skasowanych — z error_log) +- Lista usuniętych klas/metod/hooków +- Otwarte kwestie (jeśli wyszły w trakcie) + diff --git a/.paul/phases/09-finalizacja/09-03-SUMMARY.md b/.paul/phases/09-finalizacja/09-03-SUMMARY.md new file mode 100644 index 0000000..b6fbbf3 --- /dev/null +++ b/.paul/phases/09-finalizacja/09-03-SUMMARY.md @@ -0,0 +1,184 @@ +--- +phase: 09-finalizacja +plan: 03 +subsystem: cleanup +tags: [cleanup, oauth-removal, ical-consolidation, migration] + +requires: + - phase: 09-finalizacja/09-02 + provides: globalna iCal sync (export feed + import + alias) — staje się jedynym mechanizmem po usunięciu konkurencji + +provides: + - Plugin z jednym mechanizmem GCal sync (globalny iCal) + - Cleanup migration "po cichu" (Installer::migrate, idempotent, version-aware) + - Czysta baza po upgrade (4 stale meta keys + 6 stale options + per-yacht ical_import bookings + 5 cron hooków usuniętych) + - Skrócony codebase (~700 linii martwego kodu usuniętych, 3 pliki OAuth znikają) + +affects: + - 09-04 Security audit — mniej powierzchni do auditu + - 09-05 Testy + i18n + dokumentacja — mniej do udokumentowania + - przyszłe milestone'y v1.x — czysty fundament bez OAuth dependencies + +tech-stack: + added: [] + patterns: + - "Idempotent version-gated migration: Installer::migrate() porównuje get_option('yacht_booking_version') z YACHT_BOOKING_VERSION i wykonuje cleanup tylko przy upgrade" + - "Cleanup po cichu — bez admin notice, klient nie musi wykonywać żadnych akcji ręcznych" + +key-files: + created: [] + modified: + - wp-content/plugins/yacht-booking-system/yacht-booking-system.php + - wp-content/plugins/yacht-booking-system/includes/class-yacht-booking.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 + - wp-content/plugins/yacht-booking-system/admin/class-yacht-list-table.php + - wp-content/plugins/yacht-booking-system/integrations/ical/class-ical-import.php + - wp-content/plugins/yacht-booking-system/integrations/ical/class-ical-feed.php + - wp-content/plugins/yacht-booking-system/uninstall.php + deleted: + - wp-content/plugins/yacht-booking-system/integrations/google-calendar/class-sync-controller.php + - wp-content/plugins/yacht-booking-system/integrations/google-calendar/class-gcal-service.php + - wp-content/plugins/yacht-booking-system/integrations/google-calendar/class-oauth-handler.php + +key-decisions: + - "Per-yacht bookings z source 'ical_import' — usuwamy w migration (klient ponownie zaimportuje przez globalny mechanizm), zamiast migrować je do source 'ical_import_global'" + - "Migration idempotentna przez version_compare — kolejna aktywacja nie powtarza cleanup" + - "Bez admin notice po migration — klient wybrał 'po cichu'" + - "Per-yacht feedy iCal usunięte całkowicie (nie zostawione jako fallback) — model mentalny: jeden mechanizm" + +patterns-established: + - "Wersja-aware cleanup w Installer::install() — pattern do reuse w przyszłych planach refaktorujących/usuwających legacy" + - "FQN namespace + lazy require_once dla klas używanych w activation hook (przed ładowaniem bootstrap)" + +duration: ~30min +started: 2026-05-06T11:30:00Z +completed: 2026-05-06T12:00:00Z +--- + +# Phase 9 Plan 03: Cleanup OAuth + per-yacht iCal Summary + +**Wycofanie OAuth (3 pliki + cała sekcja UI), per-yacht iCal feed/import (pole "Google Calendar ID", "iCal Import URL", kolumna w yacht-list, cron) z bezgłośną migracją bazy — plugin sprowadzony do jednego mechanizmu sync (globalny iCal z 09-02).** + +## Performance + +| Metric | Value | +|--------|-------| +| Duration | ~30min | +| Tasks | 3 auto + 1 human-verify (wszystkie zaakceptowane) | +| Files modified | 10 | +| Files deleted | 3 | +| Lines removed | ~700+ (3 OAuth files + per-yacht iCal + UI + handlers) | + +## Acceptance Criteria Results + +| Criterion | Status | Notes | +|-----------|--------|-------| +| AC-1: Pliki OAuth usunięte i nie ładowane | Pass | 3 pliki + katalog `integrations/google-calendar/` usunięte. Bootstrap (`yacht-booking-system.php`, `class-yacht-booking.php`) bez require/wiring. PHP lint OK. | +| AC-2: Sekcja OAuth zniknęła z Settings | Pass | `render_google_calendar_settings()` zawiera tylko nagłówek + sekcję "Globalna synchronizacja iCal". Usunięte: handle_oauth_callback, save_gcal_credentials, callback/disconnect/credentials w process_settings_save, notice connected/disconnected. | +| AC-3: Pola per-jacht zniknęły z yacht-edit i yacht-list | Pass | yacht-edit nie ma "Google Calendar ID", "iCal Import URL", "iCal Feed URL". Ma tylko Alias. Lista jachtów bez kolumny "Google Calendar". | +| AC-4: Per-jacht iCal cron i feed wyłączone | Pass | Cron `yacht_booking_ical_import` nie rejestrowany. Rewrite rule `^yacht-ical/(\d+)/...` usunięta — URL per-yacht zwróci 404. Globalny `^yacht-ical-global/...` aktywny. | +| AC-5: Cleanup migration | Pass | `Installer::migrate()` — version-gated. Kasuje 4 meta keys (delete_post_meta_by_key), 6 opcji OAuth, bookings z source 'ical_import' (Availability::clear_booking_availability + wp_delete_post), 5 cron hooków. | +| AC-6: Globalna iCal sync bez regresji | Pass | Boundary chronił z 09-02 — wszystkie globalne metody/UI/cron nietknięte, alias zachowany. | +| AC-7: uninstall.php zaktualizowany | Pass | Dodane delete_option dla `yacht_booking_global_ical_*`, `yacht_booking_enabled`. Defensywne delete_option dla legacy gcal_* keys. | + +## Accomplishments + +- Plugin ma JEDEN spójny mechanizm sync z GCal (globalny iCal), zamiast 4 (OAuth push, OAuth pull, per-yacht iCal feed, per-yacht iCal import) — drastyczne zmniejszenie powierzchni mentalnej i bug surface +- Czysta baza po automatycznej migracji — klient nie wykonuje żadnych akcji ręcznych, niepotrzebne meta i opcje znikają przy następnej aktywacji pluginu +- Codebase odchudzony o ~700+ linii martwego kodu (3 pliki OAuth/Sync + UI/CRUD per-yacht iCal) +- Zero regresji w globalnej iCal sync ani frontendzie (kalendarz widget, REST API, CPT, availability) — boundaries respektowane +- Plugin gotowy produkcyjnie w warstwie integracji GCal — pozostają tylko 09-04 (security audit) i 09-05 (testy + i18n + docs) do zamknięcia milestone v1.0 + +## Files Created/Modified + +| File | Change | Purpose | +|------|--------|---------| +| `integrations/google-calendar/class-sync-controller.php` | **Deleted** | OAuth orchestrator usunięty całkowicie | +| `integrations/google-calendar/class-gcal-service.php` | **Deleted** | Google Calendar API calls usunięte | +| `integrations/google-calendar/class-oauth-handler.php` | **Deleted** | OAuth tokens + credentials usunięte | +| `yacht-booking-system.php` | Modified | Wycięte require + setup_cron + clear_cron Sync_Controller w activate/deactivate hooks | +| `includes/class-yacht-booking.php` | Modified | Wycięte 3 require_once + Sync_Controller::get_instance/register_cron_actions w `load_dependencies()` | +| `includes/class-yacht.php` | Modified | Usunięte `get_gcal_id()`, `update_gcal_id()` | +| `includes/class-installer.php` | Modified | Dodana `migrate()` (version-gated, idempotent), usunięty `yacht_booking_gcal_sync_enabled` z create_options | +| `admin/class-admin.php` | Modified | Wycięte: handle_oauth_callback, save_gcal_credentials, OAuth bloki w process_settings_save i display_admin_notices, cała sekcja OAuth w render_google_calendar_settings, save_yacht zapisuje tylko alias | +| `admin/views/yacht-edit.php` | Modified | Usunięte 3 wiersze tabeli (Google Calendar ID, iCal Import URL, iCal Feed URL) + 4 zmienne PHP. Pozostaje Alias. | +| `admin/class-yacht-list-table.php` | Modified | Usunięta kolumna `gcal` z get_columns + metoda column_gcal | +| `integrations/ical/class-ical-import.php` | Modified | Usunięte: const IMPORT_SOURCE, run_import, get_import_url, set_import_url, import_for_yacht, get_existing_import_map, upsert_booking, get_last_import_time. Cron 'yacht_booking_ical_import' nie rejestrowany. | +| `integrations/ical/class-ical-feed.php` | Modified | Usunięte: rewrite rule per-yacht, query var yacht_ical_id, branch per-yacht w handle_feed_request, output_ics, get_feed_token, regenerate_token, get_feed_url. Pozostaje globalna ścieżka. | +| `uninstall.php` | Modified | Dodane: yacht_booking_global_ical_*, yacht_booking_enabled. Defensywne legacy gcal_* delete_option. | + +## Decisions Made + +| Decision | Rationale | Impact | +|----------|-----------|--------| +| Usunięcie per-yacht bookings 'ical_import' w migration | Bez per-yacht importu nie będą odświeżane — lepsze UX usunąć i pozwolić ponowny globalny import niż zostawić "skamieniałe" blokady | Klient po deploy uruchamia "Importuj teraz" raz i ma świeże dane | +| Migration version-gated z version_compare | Idempotencja — kolejna aktywacja po pierwszej nie powtarza cleanup, bezpieczne dla repeated activate/deactivate | Zero ryzyka przy ręcznych re-aktywacjach lub WP auto-update | +| FQN dla `\YachtBooking\Availability` w migrate() | Activation hook ładuje Installer ręcznie przed bootstrap — autoloader może być nieaktywny | Lazy require_once jako fallback wewnątrz pętli `if (!class_exists)` | +| Defensywne delete_option dla legacy gcal_* w uninstall.php | Migration usuwa je przy upgrade, ale uninstall.php może być uruchomiony bezpośrednio na starszej wersji bez upgrade | Wszystkie ścieżki sprzątają legacy keys | +| Brak admin notice po migration | Klient w fazie planowania wybrał "po cichu" — żeby nie zaprzątać uwagi | Płynne UX, klient zauważy tylko że stare pola znikły | + +## Deviations from Plan + +### Summary + +| Type | Count | Impact | +|------|-------|--------| +| Auto-fixed | 1 | Drobny | +| Scope additions | 0 | — | +| Deferred | 0 | — | + +**Total impact:** Plan wykonany w pełni, jeden drobny auto-fix dla bezpieczeństwa. + +### Auto-fixed Issues + +**1. [Migration safety] Availability class loading w activation hook** +- **Found during:** Task 3 (Installer::migrate) +- **Issue:** Migration wywołuje `\YachtBooking\Availability::clear_booking_availability()`, ale Installer jest ładowany przez activation hook PRZED `plugins_loaded` (gdzie autoloader spl_autoload_register() jest rejestrowany). Pierwotna implementacja zakładała że Availability jest dostępne automatycznie. +- **Fix:** Dodany guard `if ( ! class_exists( '\YachtBooking\Availability' ) ) { require_once YACHT_BOOKING_PLUGIN_DIR . 'includes/class-availability.php'; }` przed pętlą usuwającą stale bookings. Dodatkowo otoczone `if (!empty($stale_bookings))` żeby nie ładować pliku gdy nie ma nic do usunięcia. +- **Files:** includes/class-installer.php +- **Verification:** PHP lint OK; logika idempotentna; w testach klient potwierdził że upgrade nie powoduje fatal error. + +### Deferred Items + +Brak. + +## Issues Encountered + +| Issue | Resolution | +|-------|------------| +| Brak konkretnych fatal errors lub regresji | — | + +## Reproduction Path (do testów regresyjnych) + +1. Po deploy FTP — aktywuj plugin (lub deactivate→activate na produkcji). Wyzwoli `Installer::install()` → `migrate()`. +2. Sprawdź WP Admin → Settings → Google Calendar: tylko sekcja "Globalna synchronizacja iCal" (z 09-02). +3. Sprawdź edycję jachtu: brak "Google Calendar ID"/"iCal Import URL"/"iCal Feed URL". Jest tylko "Alias dla Google Calendar". +4. Lista jachtów: brak kolumny "Google Calendar". +5. URL `/yacht-ical/X/token.ics` → 404. URL `/yacht-ical-global/{token}.ics` → poprawny .ics. +6. phpMyAdmin: brak meta `_yacht_gcal_id`/`_yacht_ical_*`, brak opcji `yacht_booking_gcal_*` (poza globalnymi `*_global_ical_*`), brak bookingów z source `ical_import`. +7. Druga aktywacja → migrate() nie powtarza cleanup (version match). + +## Next Phase Readiness + +**Ready:** +- Codebase czysty, 1 mechanizm GCal sync +- Migration mechanizm gotowy do reuse w przyszłych planach refaktorujących +- Plugin z punktu widzenia integracji GCal jest produkcyjnie skończony + +**Concerns:** +- Klient po deploy musi pamiętać o uruchomieniu globalnego "Importuj teraz" w Settings, żeby ponownie zaimportować eventy z Google Calendar (stare per-yacht zostały skasowane). Mitigacja: zostało udokumentowane w checkpoint verify steps. +- `yacht_booking_capabilities_added` flag jest sprawdzany raz w `Yacht_Booking::add_custom_capabilities()` — zachowany w uninstall.php. Nie ruszamy go. + +**Blockers:** None + +## Otwarte kwestie milestone v1.0 + +- 09-04: Security audit (nonce, escaping, SQL prepare, capabilities) +- 09-05: Testy + tłumaczenia .pot/.po/.mo + dokumentacja użytkownika i dewelopera + +--- +*Phase: 09-finalizacja, Plan: 03* +*Completed: 2026-05-06* diff --git a/.vscode/ftp-kr.sync.cache.json b/.vscode/ftp-kr.sync.cache.json new file mode 100644 index 0000000..3cd3bb8 --- /dev/null +++ b/.vscode/ftp-kr.sync.cache.json @@ -0,0 +1,208 @@ +{ + "ftp://host117523.hostido.net.pl@www@jachty3.pagedev.pl": { + "public_html": { + ".htaccess": { + "type": "-", + "size": 665, + "lmtime": 0, + "modified": false + }, + "index.php": { + "type": "-", + "size": 405, + "lmtime": 0, + "modified": false + }, + "license.txt": { + "type": "-", + "size": 19903, + "lmtime": 0, + "modified": false + }, + "__MACOSX": {}, + ".planning": { + "codebase": { + "ARCHITECTURE.md": { + "type": "-", + "size": 12531, + "lmtime": 1778017398128, + "modified": false + }, + "CONVENTIONS.md": { + "type": "-", + "size": 9024, + "lmtime": 1778017439483, + "modified": false + }, + "INTEGRATIONS.md": { + "type": "-", + "size": 13136, + "lmtime": 1778017420536, + "modified": false + }, + "STACK.md": { + "type": "-", + "size": 3636, + "lmtime": 1778017353336, + "modified": false + }, + "STRUCTURE.md": { + "type": "-", + "size": 8663, + "lmtime": 1778017445887, + "modified": false + }, + "TESTING.md": { + "type": "-", + "size": 6979, + "lmtime": 1778017485643, + "modified": false + } + } + }, + "readme.html": { + "type": "-", + "size": 7425, + "lmtime": 0, + "modified": false + }, + "wp-activate.php": { + "type": "-", + "size": 7349, + "lmtime": 0, + "modified": false + }, + "wp-admin": {}, + "wp-blog-header.php": { + "type": "-", + "size": 351, + "lmtime": 0, + "modified": false + }, + "wp-comments-post.php": { + "type": "-", + "size": 2323, + "lmtime": 0, + "modified": false + }, + "wp-config.php": { + "type": "-", + "size": 3764, + "lmtime": 0, + "modified": false + }, + "wp-config-sample.php": { + "type": "-", + "size": 3339, + "lmtime": 0, + "modified": false + }, + "wp-content": { + "plugins": { + "yacht-booking-system": { + "frontend": { + "assets": { + "js": { + "calendar.js": { + "type": "-", + "size": 15422, + "lmtime": 1778018642248, + "modified": false + } + }, + "css": { + "calendar.css": { + "type": "-", + "size": 12984, + "lmtime": 1778019168166, + "modified": false + }, + "calendar.css.map": { + "type": "-", + "size": 4874, + "lmtime": 0, + "modified": false + }, + "calendar.scss": { + "type": "-", + "size": 15260, + "lmtime": 1778019161179, + "modified": false + } + } + }, + "class-calendar-widget.php": { + "type": "-", + "size": 21040, + "lmtime": 1778019128363, + "modified": false + }, + "class-shortcode.php": { + "type": "-", + "size": 14528, + "lmtime": 0, + "modified": false + } + } + } + } + }, + "wp-cron.php": { + "type": "-", + "size": 5617, + "lmtime": 0, + "modified": false + }, + "wp-includes": {}, + "wp-links-opml.php": { + "type": "-", + "size": 2493, + "lmtime": 0, + "modified": false + }, + "wp-load.php": { + "type": "-", + "size": 3937, + "lmtime": 0, + "modified": false + }, + "wp-login.php": { + "type": "-", + "size": 51437, + "lmtime": 0, + "modified": false + }, + "wp-mail.php": { + "type": "-", + "size": 8727, + "lmtime": 0, + "modified": false + }, + "wp-settings.php": { + "type": "-", + "size": 31055, + "lmtime": 0, + "modified": false + }, + "wp-signup.php": { + "type": "-", + "size": 34516, + "lmtime": 0, + "modified": false + }, + "wp-trackback.php": { + "type": "-", + "size": 5214, + "lmtime": 0, + "modified": false + }, + "xmlrpc.php": { + "type": "-", + "size": 3205, + "lmtime": 0, + "modified": false + } + } + }, + "$version": 1 +} \ No newline at end of file diff --git a/wp-content/plugins/yacht-booking-system/admin/class-admin.php b/wp-content/plugins/yacht-booking-system/admin/class-admin.php index d34fb62..eee093f 100644 --- a/wp-content/plugins/yacht-booking-system/admin/class-admin.php +++ b/wp-content/plugins/yacht-booking-system/admin/class-admin.php @@ -64,27 +64,6 @@ class Admin { return; } - // Load Google Calendar classes if needed - if ( file_exists( YACHT_BOOKING_PLUGIN_DIR . 'integrations/google-calendar/class-oauth-handler.php' ) ) { - require_once YACHT_BOOKING_PLUGIN_DIR . 'integrations/google-calendar/class-oauth-handler.php'; - } - if ( file_exists( YACHT_BOOKING_PLUGIN_DIR . 'integrations/google-calendar/class-gcal-service.php' ) ) { - require_once YACHT_BOOKING_PLUGIN_DIR . 'integrations/google-calendar/class-gcal-service.php'; - } - - // Handle OAuth callback - if ( isset( $_GET['gcal_callback'] ) && isset( $_GET['code'] ) ) { - $this->handle_oauth_callback(); - } - - // Handle disconnect - if ( isset( $_POST['yacht_booking_disconnect_gcal'] ) ) { - check_admin_referer( 'yacht_booking_disconnect_gcal' ); - \YachtBooking\Integrations\GoogleCalendar\OAuth_Handler::disconnect(); - wp_safe_redirect( admin_url( 'admin.php?page=yacht-bookings-settings&tab=google-calendar&disconnected=1' ) ); - exit; - } - // Handle general settings save if ( isset( $_POST['yacht_booking_save_settings'] ) ) { check_admin_referer( 'yacht_booking_save_settings' ); @@ -105,10 +84,30 @@ class Admin { exit; } - // Handle credentials save - if ( isset( $_POST['yacht_booking_save_gcal_credentials'] ) ) { - check_admin_referer( 'yacht_booking_save_gcal_credentials' ); - $this->save_gcal_credentials(); + // Handle global iCal settings save. + if ( isset( $_POST['yacht_booking_save_global_ical'] ) ) { + check_admin_referer( 'yacht_booking_save_global_ical' ); + $import_url = isset( $_POST['global_ical_import_url'] ) ? esc_url_raw( wp_unslash( $_POST['global_ical_import_url'] ) ) : ''; + update_option( 'yacht_booking_global_ical_import_url', $import_url ); + wp_safe_redirect( admin_url( 'admin.php?page=yacht-bookings-settings&tab=google-calendar&global_ical_saved=1' ) ); + exit; + } + + // Handle global iCal token regeneration. + if ( isset( $_POST['yacht_booking_regenerate_global_ical_token'] ) ) { + check_admin_referer( 'yacht_booking_regenerate_global_ical_token' ); + \YachtBooking\Integrations\ICal\ICal_Feed::regenerate_global_token(); + wp_safe_redirect( admin_url( 'admin.php?page=yacht-bookings-settings&tab=google-calendar&token_regenerated=1' ) ); + exit; + } + + // Handle global iCal manual import trigger. + if ( isset( $_POST['yacht_booking_run_global_ical_import'] ) ) { + check_admin_referer( 'yacht_booking_run_global_ical_import' ); + $result = \YachtBooking\Integrations\ICal\ICal_Import::run_global_import(); + $arg = $result ? 'global_import_done=1' : 'global_import_failed=1'; + wp_safe_redirect( admin_url( 'admin.php?page=yacht-bookings-settings&tab=google-calendar&' . $arg ) ); + exit; } } @@ -148,24 +147,6 @@ class Admin { -
-

-
- -
-

-
- @@ -174,6 +155,38 @@ class Admin {
+
+

+
+ +
+

+
+ +
+

+
+ +
+

+
+ -
-

-
- -

+

- - -
-

-

- -
    -
  1. Google Cloud Console
  2. -
  3. -
  4. -
  5. -
  6. - -
    - https://jachty.pagedev.pl/wp-admin/admin.php?page=yacht-bookings-settings&tab=google-calendar&gcal_callback=1 -
    - -
  7. -
  8. -
- -
- - - - - - - - - - - -
- - - -
- - - -
- -

- -

-
-
- - - -
-

-

- - -

- - - -

- - -
- DEBUG - Redirect URI wysyłany do Google: -
- - - - Porównaj dokładnie z tym co masz w Google Cloud Console (character-by-character) -
- -

- -

- -
- - - - -
-

-

- - -

- -

- -

- -
- -

- -

-
-
- - -
-

-

-

- - -

-
-
- -
-

-

-
    -
  1. -
  2. -
  3. -
  4. -
  5. -
-

-
- +
+

+

+ +

- /** - * Handle OAuth callback - */ - private function handle_oauth_callback() { - if ( ! isset( $_GET['code'] ) ) { - wp_safe_redirect( admin_url( 'admin.php?page=yacht-bookings-settings&tab=google-calendar&error=1' ) ); - exit; - } +

+

+ +

+

+ + +

+
+ + + + + +
- $code = sanitize_text_field( wp_unslash( $_GET['code'] ) ); - $result = \YachtBooking\Integrations\GoogleCalendar\OAuth_Handler::authenticate( $code ); +

+

+ +

+
+ + + + + + +
+ + + + +

+ +

+ +
+

+ +

+
- if ( $result ) { - wp_safe_redirect( admin_url( 'admin.php?page=yacht-bookings-settings&tab=google-calendar&connected=1' ) ); - } else { - wp_safe_redirect( admin_url( 'admin.php?page=yacht-bookings-settings&tab=google-calendar&error=1' ) ); - } - exit; +

+

+ +

+
+ + +
+ +

+
    +
  • +
  • +
  • +
  • +
  • +
+
+ + sanitize_text_field( wp_unslash( $_POST['gcal_client_id'] ) ), - 'client_secret' => sanitize_text_field( wp_unslash( $_POST['gcal_client_secret'] ) ), - ); - - \YachtBooking\Integrations\GoogleCalendar\OAuth_Handler::save_credentials( $credentials ); - } - - wp_safe_redirect( admin_url( 'admin.php?page=yacht-bookings-settings&tab=google-calendar&saved=1' ) ); - exit; - } - /** * Process booking actions (approve, cancel, delete) */ diff --git a/wp-content/plugins/yacht-booking-system/admin/class-yacht-list-table.php b/wp-content/plugins/yacht-booking-system/admin/class-yacht-list-table.php index 5375931..f990d36 100644 --- a/wp-content/plugins/yacht-booking-system/admin/class-yacht-list-table.php +++ b/wp-content/plugins/yacht-booking-system/admin/class-yacht-list-table.php @@ -44,7 +44,6 @@ class Yacht_List_Table extends \WP_List_Table { return array( 'cb' => '', 'title' => __( 'Nazwa jachtu', 'yacht-booking' ), - 'gcal' => __( 'Google Calendar', 'yacht-booking' ), 'bookings' => __( 'Rezerwacje', 'yacht-booking' ), 'date' => __( 'Data utworzenia', 'yacht-booking' ), ); @@ -163,28 +162,6 @@ class Yacht_List_Table extends \WP_List_Table { ); } - /** - * Column Google Calendar - * - * @param object $item Item. - * @return string - */ - public function column_gcal( $item ) { - $gcal_id = Yacht::get_gcal_id( $item->ID ); - - if ( $gcal_id ) { - return sprintf( - ' %s', - esc_html__( 'Połączony', 'yacht-booking' ) - ); - } - - return sprintf( - ' %s', - esc_html__( 'Niepołączony', 'yacht-booking' ) - ); - } - /** * Column bookings count * diff --git a/wp-content/plugins/yacht-booking-system/admin/views/yacht-edit.php b/wp-content/plugins/yacht-booking-system/admin/views/yacht-edit.php index 324fe1c..98ba488 100644 --- a/wp-content/plugins/yacht-booking-system/admin/views/yacht-edit.php +++ b/wp-content/plugins/yacht-booking-system/admin/views/yacht-edit.php @@ -11,12 +11,9 @@ if ( ! defined( 'ABSPATH' ) ) { } // Get yacht data -$title = $yacht ? $yacht->post_title : ''; -$content = $yacht ? $yacht->post_content : ''; -$gcal_id = $yacht ? \YachtBooking\Yacht::get_gcal_id( $yacht->ID ) : ''; -$ical_import_url = $yacht ? \YachtBooking\Integrations\ICal\ICal_Import::get_import_url( $yacht->ID ) : ''; -$ical_feed_url = $yacht ? \YachtBooking\Integrations\ICal\ICal_Feed::get_feed_url( $yacht->ID ) : ''; -$ical_last_import = $yacht ? \YachtBooking\Integrations\ICal\ICal_Import::get_last_import_time( $yacht->ID ) : ''; +$title = $yacht ? $yacht->post_title : ''; +$content = $yacht ? $yacht->post_content : ''; +$gcal_alias = $yacht ? \YachtBooking\Yacht::get_gcal_alias( $yacht->ID ) : ''; $page_title = $yacht ? __( 'Edytuj Jacht', 'yacht-booking' ) : __( 'Dodaj Jacht', 'yacht-booking' ); ?> @@ -89,100 +86,28 @@ $page_title = $yacht ? __( 'Edytuj Jacht', 'yacht-booking' ) : __( 'Dodaj Jacht' - + -