Files
2026-05-07 14:57:59 +02:00

14 KiB

phase, plan, subsystem, tags, requires, provides, affects, tech-stack, key-files, key-decisions, patterns-established, duration, started, completed
phase plan subsystem tags requires provides affects tech-stack key-files key-decisions patterns-established duration started completed
09-finalizacja 04 api, ui, integrations
ical
fullcalendar
elementor
rest
privacy
phase provides
09-finalizacja globalna sync iCal (09-02), cleanup OAuth (09-03)
tryb sync iCal "wspólny kalendarz" (storage bez per-yacht matchingu)
REST endpoint /availability/all (agregacja + privacy)
widget Elementor + shortcode [yacht_calendar_all]
paleta kolorów per-jacht (Rest_Controller::YACHT_COLOR_PALETTE)
privacy
tytuły eventów nie zawierają nazwisk klientów (REST + JS)
security audit
dokumentacja
added patterns
View helper pattern (Calendar_All_View) — render wspólny dla widgetu i shortcode
Eager-load REST controller (constants/static methods used in frontend)
Privacy-by-default
REST endpoint nie wystawia nazwisk klientów
created modified
wp-content/plugins/yacht-booking-system/frontend/class-calendar-widget-all.php
wp-content/plugins/yacht-booking-system/frontend/assets/css/calendar-all.css
wp-content/plugins/yacht-booking-system/frontend/assets/js/calendar-all.js
wp-content/plugins/yacht-booking-system/api/class-rest-controller.php
wp-content/plugins/yacht-booking-system/integrations/ical/class-ical-import.php
wp-content/plugins/yacht-booking-system/includes/class-settings.php
wp-content/plugins/yacht-booking-system/includes/class-installer.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/frontend/class-shortcode.php
wp-content/plugins/yacht-booking-system/yacht-booking-system.php
Tryb sync `global` = osobna ścieżka cleanup, dwie stałe source (per-yacht / global)
Privacy: title eventów na REST = nazwa jachtu (per_yacht) lub generyczne 'Rezerwacja' (global), bez customer_name
View helper `Calendar_All_View::render()` — wspólny markup widget + shortcode
Eager-load Rest_Controller w load_dependencies() — używany przez frontend View, nie tylko REST
Half-day visual: dynamiczny gradient JS na bazie szerokości komórki dnia (FC nie ma natywnej obsługi half-day w dayGrid)
Kolor wspólnych eventów: jasnoniebieski #7fb3d5 (po iteracjach: #7f8c8d → #bc1834 → #7fb3d5)
Privacy-by-default w REST: tytuły eventów bez customer_name nawet w trybie per_yacht
Settings z whitelistą wartości (`per_yacht`/`global`) + fallback do bezpiecznego defaultu
Stała paleta kolorów współdzielona REST ↔ frontend (Rest_Controller::YACHT_COLOR_PALETTE)
~120min 2026-05-07T11:30:00Z 2026-05-07T13:30:00Z

Phase 09 Plan 04: Globalna sync iCal + widget wszystkich jachtów

Plugin obsługuje teraz dwa tryby synchronizacji iCal (per-jacht / wspólny) i ma drugi widget kalendarza pokazujący zajętość wszystkich jachtów na jednej siatce z paletą kolorów per-jacht, half-day gradientem i ciemnym formularzem zapytania po prawej stronie.

Performance

Metric Value
Duration ~120min (z iteracjami UX po checkpoincie)
Started 2026-05-07T11:30:00Z
Completed 2026-05-07T13:30:00Z
Tasks 4 auto + 1 checkpoint + 5 iteracji UX po checkpoincie
Files modified 8 zmodyfikowanych + 3 nowe + 1 testowy (test-overlap-bookings.php)

Acceptance Criteria Results

Criterion Status Notes
AC-1: Settings — przełącznik trybu sync iCal Pass Pole select w sekcji "Synchronizacja", domyślnie per_yacht
AC-2: Import iCal w trybie globalnym (wszystkie eventy) Pass Wszystkie eventy z basic.ics importowane, brak wpisów do wp_yacht_availability
AC-3: Import iCal w trybie per_yacht (bez regresji) Pass Stara ścieżka run_per_yacht_mode() działa identycznie, własna stała cleanup
AC-4: REST endpoint /availability/all Pass Zwraca FullCalendar events z timed 12:00→12:00 i kolorami
AC-5: Widget + shortcode Pass Po iteracjach: ciemne tło, formularz inquiry z select jachtów, bez tytułów eventów
AC-6: Auto paleta kolorów per jacht Pass YACHT_COLOR_PALETTE (8 kolorów) deterministyczna po yacht_id

Accomplishments

  • Tryb global iCal — klient prowadzi jeden wspólny Google Calendar, wszystkie eventy (32 z basic.ics) są importowane bez filtrowania prefiksem; nie blokują dostępności jachtów (yacht_id=0).
  • Wspólny widget z formularzem inquiry[yacht_calendar_all] + Elementor "Kalendarz Jachtów (wszystkie)" pokazuje siatkę miesięczną z paskami rezerwacji w kolorach palety per-jacht (lub jednolity jasnoniebieski w trybie global), formularz "Zapytaj o rezerwację" po prawej w ciemnym stylu identycznym jak /rezerwacja-maja/.
  • Privacy-by-default — REST endpoint /availability/all nie wystawia customer_name w title eventów; w trybie global tytuł = generyczne "Rezerwacja", w per_yacht = sama nazwa jachtu. Defense-in-depth: JS eventContent zwraca pusty html (nawet gdyby title trafił do REST, nie wyrenderuje się w DOM).
  • Half-day visual — dynamiczny gradient JS na pierwszym/ostatnim dniu rezerwacji (yacht zwracany/odbierany w południe), liczony na bazie szerokości komórki dnia (FullCalendar dayGrid nie ma natywnej obsługi).

Files Created/Modified

File Change Purpose
wp-content/plugins/yacht-booking-system/yacht-booking-system.php Modified Bump wersji 1.0.0 → 1.1.0 (uruchamia Installer::install + cache busting)
includes/class-settings.php Modified get_ical_sync_mode() z whitelistą wartości
includes/class-installer.php Modified Default option yacht_booking_ical_sync_mode = per_yacht
includes/class-yacht-booking.php Modified Eager-load Rest_Controller, rejestracja widgetu, conditional enqueue, detekcja shortcode/widget
admin/class-admin.php Modified Pole select trybu sync + obsługa zapisu w process_settings_save()
integrations/ical/class-ical-import.php Modified Rozgałęzienie run_per_yacht_mode() / run_global_calendar_mode(), nowa stała GLOBAL_CALENDAR_SOURCE, metody upsert_global_calendar_event(), get_existing_global_calendar_map()
api/class-rest-controller.php Modified Stałe YACHT_COLOR_PALETTE + GLOBAL_EVENT_COLOR, route + metoda get_all_availability(), get_yacht_color_palette(), privacy w title
frontend/class-shortcode.php Modified Shortcode [yacht_calendar_all]
frontend/class-calendar-widget-all.php Created Widget Elementor Calendar_Widget_All + helper Calendar_All_View (server-side legenda + formularz inquiry z select jachtów)
frontend/assets/css/calendar-all.css Created Tła komórek emulujące paletę single-yacht (semi-transparent na ciemnym tle), styl select, ukryte tytuły eventów
frontend/assets/js/calendar-all.js Created FullCalendar init, dynamiczny gradient half-day, submit handler dla formularza inquiry z dropdownem jachtów
test-overlap-bookings.php Created (root) Test helper dodający 2 nakładające się eventy (do usunięcia po teście)

Decisions Made

Decision Rationale Impact
Dwie stałe source (ical_import_global per-yacht, ical_global_calendar global) Pozwala niezależny cleanup w obu trybach bez krzyżowych usunięć Przełączanie trybów nie usuwa eventów z drugiego trybu
Privacy: brak customer_name w REST title Wcześniej title zawierało "Maja — Jan Kowalski" — nazwiska klientów na publicznym REST Nawet po inspekcji DOM/API nazwisk nie ma
View helper Calendar_All_View::render() zamiast duplikacji widget+shortcode DRY Zmiana markupu w jednym miejscu
Eager-load Rest_Controller w load_dependencies() Frontend View używa stałych palety + statyk metod Bez tego: Class 'Rest_Controller' not found przy renderze
Half-day przez dynamiczny gradient JS (a nie czyste CSS) FullCalendar dayGrid nie ma natywnej obsługi half-day; CSS nie zna szerokości segmentu Wymaga requestAnimationFrame w eventDidMount
Klasa wrappera yacht-calendar-all-wrapper (bez yacht-calendar-wrapper) Calendar.js inicjalizuje wszystko z .yacht-calendar-wrapper → kolizja Drugi widget niezależny od starego JS
Kolor wspólnych eventów: #7fb3d5 (jasnoniebieski) Iteracje z klientem: szary #7f8c8d → czerwony #bc1834 (zbyt agresywny) → jasnoniebieski Spójny z legendą + komfort wizualny
Tła komórek rgba(245,249,255, 0.4) na #0e2036 Emulacja efektu yacht-day-available bg-event nad ciemnym parent containerem w /rezerwacja-maja/ Spójny styl z istniejącym widgetem per-jacht

Deviations from Plan

Summary

Type Count Impact
Auto-fixed 6 UX poprawki po checkpoincie + privacy hardening
Scope additions 1 Privacy w REST (poza pierwotnym scope)
Deferred 0 Wszystko ukończone

Total impact: Solidne UX iteracje + bonus privacy hardening (chroni przed wyciekiem nazwisk klientów).

Auto-fixed Issues

1. Path discrepancies — assets w frontend/assets/ zamiast root assets/

  • Found during: Task 4 (widget assets)
  • Issue: Plan referował assets/js/, assets/css/, admin/views/settings-page.php — w projekcie tych ścieżek nie ma
  • Fix: Użyłem faktycznej struktury (frontend/assets/{css,js}/, formularz settings inline w class-admin.php)
  • Verification: Pliki utworzone w prawidłowych miejscach, conditional enqueue działa
  • Commit: część zmiany w class-yacht-booking.php

2. Class 'Rest_Controller' not found przy frontend renderze

  • Found during: Po pierwszym deploy (raportowane przez klienta)
  • Issue: Rest_Controller ładowany lazy w register_rest_routes(), View używa stałych palety przy frontend render
  • Fix: Dodano require_once api/class-rest-controller.php w Yacht_Booking::load_dependencies() (eager)
  • Verification: Brak fatal errors po reload
  • Commit: includes/class-yacht-booking.php

3. Brakujący formularz inquiry + brakująca legenda + brakująca instrukcja

  • Found during: Po checkpoincie human-verify
  • Issue: Pierwsza wersja widgetu była tylko kalendarzem; klient oczekiwał layoutu jak na /rezerwacja-maja/ (calendar + form right)
  • Fix: Dodano Calendar_All_View render z .yacht-inquiry-layout, server-side legenda (działa nawet przed JS), instrukcję, formularz inquiry z <select name="yacht_id"> dla wyboru jachtu, własny submit handler w JS
  • Verification: Playwright snapshot — wszystko widoczne
  • Commit: class-calendar-widget-all.php, calendar-all.css, calendar-all.js

4. Kalendarz nie renderował się (tylko nagłówki dni)

  • Found during: Po dodaniu layoutu 2-kolumnowego
  • Issue: FullCalendar height: '100%' w gridzie się nie liczyło → komórki collapsed
  • Fix: Wysokość przekazywana przez data-height na wrapperze, JS odczytuje i podaje FC jako liczbę pikseli (heightPx)
  • Verification: Playwright eval — fcDayGridRect ma poprawną wysokość
  • Commit: calendar-all.js + class-calendar-widget-all.php

5. Select formularza w jasnym natywnym stylu

  • Found during: Po dodaniu formularza inquiry
  • Issue: calendar.css ma reguły dla input[type=text|email|tel] ale BRAK dla <select> → biały tekst, czarne tło, natywna strzałka
  • Fix: Dodano w calendar-all.css regułę .yacht-inquiry-form select z analogicznym stylem (semi-transparent biały bg, custom SVG strzałka, dark <option>)
  • Verification: Playwright eval — bg/color/border zgodne z innymi inputami
  • Commit: calendar-all.css

6. Privacy gap — nazwiska klientów w REST title

  • Found during: Iteracja "ukryj nazwy na zajętych dniach"
  • Issue: REST title = "Maja — Jan Kowalski" — wrażliwe dane na publicznym endpointcie
  • Fix: REST title to teraz: w trybie global "Rezerwacja", w per_yacht sama nazwa jachtu (bez customer_name). JS eventContent zwraca pusty html (defense-in-depth)
  • Verification: Playwright eval /availability/all — title bez nazwisk
  • Commit: class-rest-controller.php, calendar-all.js, calendar-all.css

Deferred Items

None.

Issues Encountered

Issue Resolution
Brak php w PATH środowiska deweloperskiego (PowerShell + WSL) Manualne php -l przez klienta podczas checkpointu human-verify
FullCalendar height: '100%' w grid container collapsuje Pixel value przekazywany przez data-attribute
Tło kalendarza wyglądało "jasno" mimo poprawnej palety komórek Klient oczekiwał ciemnego efektu jak /rezerwacja-maja/, gdzie tło to bg-eventy semi-transparent nad ciemnym parentem; emulacja przez background: #0e2036 na container + rgba(245,249,255, 0.4) na komórkach
Klasa yacht-calendar-wrapper powodowała kolizję z calendar.js (per-jacht) Usunięta z roota nowego widgetu

Skill Audit

.paul/SPECIAL-FLOWS.md nie istnieje — skill audit pominięty.

Next Phase Readiness

Ready:

  • Plugin produkcyjnie obsługuje 2 tryby sync iCal (ostatnia funkcjonalna brakująca cecha)
  • Privacy-hardening REST endpointów (precedens na security audit w 09-05)
  • Widget zbiorczy gotowy do publicznego użycia (read-only z formularzem inquiry)

Concerns:

  • test-overlap-bookings.php w root projektu — do skasowania z FTP po teście (nie commitować)
  • Brak automatycznych testów regresji (zgodnie z CLAUDE.md — testy manualne)
  • Privacy-hardening REST tylko w nowym endpointcie /availability/all. Stary /availability/{yacht_id} zwraca tylko status dnia — bez customer_name — OK.

Blockers:

  • None.

Phase: 09-finalizacja, Plan: 04 Completed: 2026-05-07