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 |
|
|
|
|
|
|
|
|
~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/allnie wystawiacustomer_namewtitleeventów; w trybie global tytuł = generyczne "Rezerwacja", w per_yacht = sama nazwa jachtu. Defense-in-depth: JSeventContentzwraca 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 wclass-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.phpwYacht_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_Viewrender 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-heightna 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 selectz 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). JSeventContentzwraca 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.phpw 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