From 28b7a1dd543d78c2fcac39caf95fda62cee09279 Mon Sep 17 00:00:00 2001 From: Jacek Pyziak Date: Fri, 8 May 2026 23:56:37 +0200 Subject: [PATCH] feat(05-purchase-redirect-hardening): harden purchase redirect tracking Phase 5 complete: - guard purchase event per transaction in sessionStorage - restore saved consent before GTM and purchase - add centered Przelewy24 countdown redirect --- .paul/PROJECT.md | 8 +- .paul/ROADMAP.md | 71 ++++---- .paul/STATE.md | 39 ++--- .paul/changelog/2026-05-08.md | 8 + .../05-01-PLAN.md | 165 ++++++++++++++++++ .../05-01-SUMMARY.md | 138 +++++++++++++++ templates/site/layout-logged.php | 32 ++++ templates/tickets/przelewy24.php | 62 ++++++- 8 files changed, 457 insertions(+), 66 deletions(-) create mode 100644 .paul/phases/05-purchase-redirect-hardening/05-01-PLAN.md create mode 100644 .paul/phases/05-purchase-redirect-hardening/05-01-SUMMARY.md diff --git a/.paul/PROJECT.md b/.paul/PROJECT.md index 50b468a..ef9df2b 100644 --- a/.paul/PROJECT.md +++ b/.paul/PROJECT.md @@ -15,6 +15,8 @@ Uzytkownicy moga szybko i bezpiecznie kupic bilety online oraz otrzymac natychmi - [x] Event purchase capturuje 100% zamowien - fires przy skladaniu, nie przy powrocie z P24 (Phase 2) - [x] Zgodnosc z RODO - baner zgody na cookies z Google Consent Mode v2 (Phase 3) - [x] Baner cookies dziala bez bledu `injectScripts is not defined` (Phase 4) +- [x] Event purchase ma zabezpieczenie przed duplikatem przy odswiezeniu strony Przelewy24 (Phase 5) +- [x] Przekierowanie do Przelewy24 dziala automatycznie po 5 sekundach z czytelnym komunikatem (Phase 5) ### Should Have - [x] Spojny tracking analityczny dla zdarzen ecommerce @@ -38,6 +40,8 @@ Uzytkownicy moga szybko i bezpiecznie kupic bilety online oraz otrzymac natychmi | cookieNoticePro.init() zamiast $.fn.cookieNoticePro() | Phase 3 | Zgodnie z dokumentacja biblioteki | | Consent Mode v2 default-denied przed GTM snippetem | Phase 3 | Wymog Google od marca 2024 | | Usuniecie niezdefiniowanego injectScripts() | Phase 4 | Naprawia blad konsoli przy cookies bez zmiany GTM/Consent Mode | +| Purchase guard w sessionStorage per transaction_id | Phase 5 | Chroni przed duplikatem eventu przy odswiezeniu strony | +| Restore zapisanych zgod przed GTM | Phase 5 | Purchase uruchamia sie z poprawnym stanem Consent Mode | ## Success Criteria - Event purchase trafia do data layer po zlozeniu zamowienia (osiagniete - Phase 2) @@ -45,7 +49,9 @@ Uzytkownicy moga szybko i bezpiecznie kupic bilety online oraz otrzymac natychmi - Integracja nie wplywa negatywnie na istniejacy checkout - Baner cookies zgodny z RODO + Google Consent Mode v2 (osiagniete - Phase 3) - Baner cookies nie generuje bledu `injectScripts is not defined` (osiagniete - Phase 4) +- Purchase nie duplikuje sie po odswiezeniu strony Przelewy24 w tej samej sesji przegladarki (osiagniete - Phase 5) +- Przelewy24 redirect jest automatyczny i poprzedzony czytelnym alertem z odliczaniem (osiagniete - Phase 5) --- *Created: 2026-04-19 20:20* -*Last updated: 2026-05-08 after Phase 4 (v0.3 hotfix complete)* +*Last updated: 2026-05-08 after Phase 5 (v0.4 complete)* diff --git a/.paul/ROADMAP.md b/.paul/ROADMAP.md index da053c1..adcfa40 100644 --- a/.paul/ROADMAP.md +++ b/.paul/ROADMAP.md @@ -1,15 +1,19 @@ # Roadmap: bilety.brzezovka.pl ## Overview -Projekt obejmuje sprzedaz biletow online, tracking ecommerce oraz zgodnosc cookies/RODO. Ostatnia iteracja to hotfix banera cookies po wykryciu bledu JavaScript w CookieNoticePro. +Projekt obejmuje sprzedaz biletow online, tracking ecommerce oraz zgodnosc cookies/RODO. Aktualna iteracja domyka tracking purchase na stronie Przelewy24: jednorazowe odpalenie eventu, poprawne zgody i automatyczne przekierowanie do platnosci. ## Current Milestone -**v0.3 Cookie Notice Hotfix** (v0.3.0) +**v0.4 Purchase Redirect Hardening** (v0.4.0) Status: Complete (2026-05-08) Phases: 1 of 1 complete ## Previous Milestones +### v0.3 Cookie Notice Hotfix +Status: Complete (2026-05-08) +Phases: 1 of 1 complete + ### v0.2 Analytics & Privacy Status: Complete (2026-04-26) Phases: 3 of 3 complete @@ -26,6 +30,7 @@ Phases: 1 of 1 complete | 2 | Purchase Event Pre-Payment | 1 | Complete | 2026-04-26 | | 3 | Cookie Consent Banner | 1 | Complete | 2026-04-26 | | 4 | Cookie Notice Bugfix | 1 | Complete | 2026-05-08 | +| 5 | Purchase Redirect Hardening | 1 | Complete | 2026-05-08 | ## Phase Details @@ -42,18 +47,7 @@ Phases: 1 of 1 complete ### Phase 2: Purchase Event Pre-Payment (Complete) **Goal:** Przeniesc event purchase do momentu przekierowania na bramke platnicza po zlozeniu zamowienia, przed platnoscia Przelewy24. -**Depends on:** Phase 1 (purchase payload builder already implemented) -**Research:** Not needed - -**Context:** -- GTM (GTM-TW9WCD9J) jest wdrozony w `templates/site/layout-logged.php`. -- Event purchase zostal przeniesiony na strone `przelewy24`. -- Strona `przelewy24.php` auto-submits formularz, wiec tracking korzysta z beacon transport. - -**Scope:** -- Wywolanie `buildPurchaseDataLayer()` w metodzie `przelewy24()` kontrolera. -- Dodanie dataLayer push do `templates/tickets/przelewy24.php`. -- Usuniecie purchase push z `templates/tickets/order-confirm.php`. +**Depends on:** Phase 1 **Plans:** - [x] 02-01: Przeniesienie eventu purchase na strone przelewy24 (UNIFY complete) @@ -64,18 +58,6 @@ Phases: 1 of 1 complete **Goal:** Wdrozyc baner zgody na cookies (CookieNoticePro) z Google Consent Mode v2 i naprawic blad analityki w bibliotece. **Depends on:** Phase 2 -**Research:** Not needed - -**Context:** -- Biblioteka: `libraries/CookieNoticePro/`. -- Consent Mode v2 musi byc przed snippetem GTM w ``. -- Tylko `templates/site/layout-logged.php` jest uzywany przez glowne widoki. - -**Scope:** -- Pliki CookieNoticePro w `libraries/CookieNoticePro/`. -- Naprawa `analytics_storage: denied` przy braku zgody analytics. -- Consent Mode v2 default przed GTM w `layout-logged.php`. -- Integracja CSS/JS banera + inicjalizacja `cookieNoticePro.init()`. **Plans:** - [x] 03-01: Integracja CookieNoticePro + Consent Mode v2 (UNIFY complete) @@ -85,22 +67,33 @@ Phases: 1 of 1 complete ### Phase 4: Cookie Notice Bugfix (Complete) **Goal:** Naprawic blad JavaScript `Uncaught ReferenceError: injectScripts is not defined` w CookieNoticePro. -**Depends on:** Phase 3 (CookieNoticePro already integrated) -**Research:** Not needed (root cause is visible in local source) - -**Context:** -- `libraries/CookieNoticePro/cookienoticepro.script.js` wywolywal `injectScripts()` w dwoch miejscach. -- Funkcja `injectScripts` nie istnieje w tej kopii biblioteki. -- Blad wystepowal po kliknieciu akceptacji cookies oraz mogl wystapic przy inicjalizacji z zapisanymi zgodami. - -**Scope:** -- Usuniecie wywolan `injectScripts()`. -- Zachowanie `cookieNoticePro.init()` w `templates/site/layout-logged.php`. -- Zachowanie Google Consent Mode v2 i GTM bez zmian. +**Depends on:** Phase 3 **Plans:** - [x] 04-01: Naprawa undefined `injectScripts` w CookieNoticePro (UNIFY complete) +--- + +### Phase 5: Purchase Redirect Hardening + +**Goal:** Zabezpieczyc `purchase` przed ponownym wywolaniem po odswiezeniu strony Przelewy24 i przywrocic automatyczne przekierowanie do Przelewy24 po 5 sekundach z widocznym odliczaniem. +**Depends on:** Phase 2 (purchase pre-payment), Phase 3/4 (CookieNoticePro + Consent Mode) +**Research:** Not needed + +**Context:** +- `purchase` jest wypychany w `templates/tickets/przelewy24.php`. +- Manualny test potwierdzil, ze event uruchamia sie poprawnie po zatrzymaniu auto-submit. +- Zapisane zgody cookies musza byc przywrocone przed GTM i przed `purchase`. +- Obecny przycisk byl tylko tymczasowy do testu. + +**Scope:** +- Client-side guard w `templates/tickets/przelewy24.php` na bazie `sessionStorage` i `transaction_id`. +- Komunikat + countdown 5s + automatyczny submit formularza Przelewy24. +- Zachowanie restore zgody w `templates/site/layout-logged.php`. + +**Plans:** +- [x] 05-01: Jednorazowy purchase + redirect countdown do Przelewy24 (UNIFY complete) + --- *Roadmap created: 2026-04-19* -*Last updated: 2026-05-08 - v0.3 Cookie Notice Hotfix complete* +*Last updated: 2026-05-08 - v0.4 Purchase Redirect Hardening complete* diff --git a/.paul/STATE.md b/.paul/STATE.md index a89d4be..ca87a40 100644 --- a/.paul/STATE.md +++ b/.paul/STATE.md @@ -5,19 +5,19 @@ See: .paul/PROJECT.md (updated 2026-05-08) **Core value:** Uzytkownicy moga szybko i bezpiecznie kupic bilety online oraz otrzymac natychmiastowe potwierdzenie zakupu. -**Current focus:** v0.3 Cookie Notice Hotfix - COMPLETE +**Current focus:** v0.4 Purchase Redirect Hardening - COMPLETE ## Current Position -Milestone: v0.3 Cookie Notice Hotfix - COMPLETE -Phase: 1 of 1 (Cookie Notice Bugfix) - Complete -Plan: 04-01 complete +Milestone: v0.4 Purchase Redirect Hardening - COMPLETE +Phase: 1 of 1 (Purchase Redirect Hardening) - Complete +Plan: 05-01 complete Status: Milestone complete - ready for next milestone -Last activity: 2026-05-08 - Phase 4 complete, v0.3 hotfix shipped +Last activity: 2026-05-08 - Phase 5 complete, v0.4 shipped Progress: - Milestone: [##########] 100% -- Phase 4: [##########] 100% +- Phase 5: [##########] 100% ## Loop Position @@ -44,19 +44,16 @@ Documents: `.paul/codebase/` (8 files - stack, architecture, structure, conventi - 2026-04-26: `cookieNoticePro.init()` used instead of `$.fn.cookieNoticePro()`. - 2026-04-26: Consent Mode v2 default-denied initialized before the GTM snippet. - 2026-05-08: Undefined `injectScripts()` calls removed from CookieNoticePro instead of adding a no-op stub. +- 2026-05-08: Manual redirect pause confirmed purchase fires; saved consent must be restored before GTM/purchase. -### Cookie Consent (Phase 3 - COMPLETE) -- Library: `libraries/CookieNoticePro/`. -- Analytics denied bug fixed around line 351. -- Additional fixes: CSS initial hide for `acceptBtnSettingsLabel`, Bootstrap 5 compatibility reset. -- Consent Mode v2 init is before the GTM snippet in `templates/site/layout-logged.php`. - -### Cookie Notice Hotfix (Phase 4 - COMPLETE) -- Reported browser error: `Uncaught ReferenceError: injectScripts is not defined`. -- Root cause: `libraries/CookieNoticePro/cookienoticepro.script.js` called `injectScripts()` but this function was absent in the local library copy. -- Applied fix: removed both `injectScripts()` calls from `libraries/CookieNoticePro/cookienoticepro.script.js`. -- Verification passed: no `injectScripts` references remain, `node --check` passes, and layout still contains Consent Mode v2, GTM, and `cookieNoticePro.init()`. -- Summary: `.paul/phases/04-cookie-notice-bugfix/04-01-SUMMARY.md`. +### Current Plan Context +- Plan path: `.paul/phases/05-purchase-redirect-hardening/05-01-PLAN.md`. +- Current uncommitted source changes include `templates/site/layout-logged.php` consent restore and `templates/tickets/przelewy24.php` temporary manual redirect button. +- Applied changes: `templates/tickets/przelewy24.php` now guards purchase with `sessionStorage` per transaction and auto-submits to Przelewy24 after a 5-second countdown; `templates/site/layout-logged.php` preserves saved consent restore before GTM. +- Final UI adjustment: visible fallback button removed; redirect message is a centered Bootstrap alert with countdown. +- Verification passed: PHP lint for both modified templates, grep checks for purchase guard/countdown/consent restore, and user browser approval. +- Summary: `.paul/phases/05-purchase-redirect-hardening/05-01-SUMMARY.md`. +- Existing unrelated uncommitted change: `.vscode/ftp-kr.sync.cache.json` must remain untouched. ### Deferred Issues None. @@ -65,16 +62,16 @@ None. None. ### Git State -Last commit: current phase commit (`feat(04-cookie-notice-bugfix): fix CookieNoticePro injectScripts error`) +Last commit: current phase commit (`feat(05-purchase-redirect-hardening): harden purchase redirect tracking`) Branch: main Feature branches merged: none ## Session Continuity Last session: 2026-05-08 -Stopped at: v0.3 hotfix milestone complete +Stopped at: v0.4 milestone complete Next action: Start next milestone when needed -Resume file: .paul/phases/04-cookie-notice-bugfix/04-01-SUMMARY.md +Resume file: .paul/phases/05-purchase-redirect-hardening/05-01-SUMMARY.md --- *STATE.md - Updated after every significant action* diff --git a/.paul/changelog/2026-05-08.md b/.paul/changelog/2026-05-08.md index 6be8668..2eb0f2f 100644 --- a/.paul/changelog/2026-05-08.md +++ b/.paul/changelog/2026-05-08.md @@ -5,6 +5,9 @@ - [Phase 4, Plan 01] Naprawiono blad `Uncaught ReferenceError: injectScripts is not defined` w CookieNoticePro. - Usunieto dwa wywolania niezdefiniowanego `injectScripts()` z obslugi akceptacji cookies i inicjalizacji przy zapisanej zgodzie. - Zweryfikowano skladnie pliku JS oraz obecnosc `cookieNoticePro.init()`, Consent Mode v2 i GTM w layoucie. +- [Phase 5, Plan 01] Zabezpieczono `purchase` przed ponownym wywolaniem po odswiezeniu strony Przelewy24. +- Dodano restore zapisanych zgod cookies przed GTM, aby `purchase` korzystalo z poprawnego Consent Mode. +- Przywrocono automatyczne przekierowanie do Przelewy24 po 5 sekundach z wycentrowanym alertem i odliczaniem. ## Zmienione pliki @@ -13,3 +16,8 @@ - `.paul/phases/04-cookie-notice-bugfix/04-01-SUMMARY.md` - `.paul/STATE.md` - `.paul/ROADMAP.md` +- `templates/tickets/przelewy24.php` +- `templates/site/layout-logged.php` +- `.paul/phases/05-purchase-redirect-hardening/05-01-PLAN.md` +- `.paul/phases/05-purchase-redirect-hardening/05-01-SUMMARY.md` +- `.paul/PROJECT.md` diff --git a/.paul/phases/05-purchase-redirect-hardening/05-01-PLAN.md b/.paul/phases/05-purchase-redirect-hardening/05-01-PLAN.md new file mode 100644 index 0000000..494a9bb --- /dev/null +++ b/.paul/phases/05-purchase-redirect-hardening/05-01-PLAN.md @@ -0,0 +1,165 @@ +--- +phase: 05-purchase-redirect-hardening +plan: 01 +type: execute +wave: 1 +depends_on: [] +files_modified: + - templates/tickets/przelewy24.php + - templates/site/layout-logged.php +autonomous: true +delegation: off +--- + + +## Goal +Zabezpieczyc event `purchase` przed ponownym wywolaniem po odswiezeniu strony Przelewy24 i przywrocic automatyczne przekierowanie do Przelewy24 z komunikatem oraz odliczaniem 5 sekund. + +## Purpose +Tracking ecommerce ma rejestrowac jedno zamowienie tylko raz w przegladarce, a uzytkownik ma po zlozeniu zamowienia zostac automatycznie przekierowany do platnosci po krotkim czasie pozwalajacym GTM przetworzyc event. + +## Output +Zmodyfikowane `templates/tickets/przelewy24.php` oraz `templates/site/layout-logged.php`. + + + + +- No clarifications needed - uzytkownik potwierdzil, ze `purchase` dziala po przycisku, ale wymaga zabezpieczenia przed odswiezeniem i powrotu automatycznego przekierowania z odliczaniem 5s. +- Przyjete rozwiazanie: blokada duplikatu w `sessionStorage` per `transaction_id`, bo nie wymaga zmiany DB i chroni przed refresh w tej samej sesji przegladarki. + + +## Project Context +@.paul/PROJECT.md +@.paul/ROADMAP.md +@.paul/STATE.md + +## Prior Work +@.paul/phases/02-purchase-event-prepayment/02-01-SUMMARY.md +@.paul/phases/03-cookie-consent/03-01-SUMMARY.md +@.paul/phases/04-cookie-notice-bugfix/04-01-SUMMARY.md + +## Source Files +@templates/tickets/przelewy24.php +@templates/site/layout-logged.php +@autoload/controls/class.Tickets.php + + + + +## AC-1: Purchase fires only once per browser session and transaction +```gherkin +Given user lands on /tickets/przelewy24/order=HASH with a valid purchase payload +When the page is loaded for the first time in the current browser session +Then the page pushes ecommerce reset and `event: purchase` to `window.dataLayer` +``` + +## AC-2: Refresh does not duplicate purchase +```gherkin +Given the same browser session already sent purchase for the same transaction_id +When the user refreshes /tickets/przelewy24/order=HASH +Then the page does not push another `event: purchase` for that transaction_id +``` + +## AC-3: Auto redirect returns with visible countdown +```gherkin +Given the user lands on the Przelewy24 redirect page +When the page finishes loading +Then a message says the user will be redirected to Przelewy24 and a visible countdown starts at 5 seconds before the form submits automatically +``` + +## AC-4: Saved cookie consent is restored before GTM and purchase +```gherkin +Given the user previously accepted analytics or marketing cookies +When a new page loads +Then saved CookieNoticePro preferences update Google Consent Mode before GTM and before the purchase event can be pushed +``` + + + + + + + Task 1: Add one-time purchase guard + templates/tickets/przelewy24.php + + Replace the unconditional `window.dataLayer.push(...)` block with guarded JavaScript: + - JSON-encode the existing purchase payload as now. + - Read `transaction_id` from `purchaseDataLayer.ecommerce.transaction_id`. + - Build a stable session key, e.g. `brzezovka_purchase_sent_` + transaction_id. + - If no session key exists, push `{ ecommerce: null }` and the purchase payload, then set the session key. + - If the key exists, skip the purchase push. + - If `sessionStorage` is unavailable, fail open and still push purchase once for that page load. + Avoid changing backend payload structure in `autoload/controls/class.Tickets.php`. + + rg -n "sessionStorage|brzezovka_purchase_sent_|dataLayer.push" templates/tickets/przelewy24.php + AC-1 and AC-2 satisfied. + + + + Task 2: Restore auto redirect with five second countdown + templates/tickets/przelewy24.php + + Replace the temporary submit button with: + - A visible message explaining automatic redirect to Przelewy24. + - A visible countdown starting at 5 seconds. + - JavaScript that updates the countdown every second and submits `#form_data` after 5 seconds. + - Keep a normal submit button as fallback/manual action only if JavaScript is delayed or user wants to continue immediately. + Ensure the purchase guard executes before the redirect timer submits the form. + + rg -n "redirectCountdown|setInterval|setTimeout|form_data|Przelewy24" templates/tickets/przelewy24.php + AC-3 satisfied. + + + + Task 3: Keep saved consent restore before GTM + templates/site/layout-logged.php + + Preserve the current Consent Mode restore block added after default denied and before the GTM snippet: + - Read `cnp_consent` and `cnp_prefs` cookies. + - If consent is true, update analytics and marketing consent according to saved preferences. + - Keep the GTM snippet after this restore block. + Improve only if needed for syntax or robustness; do not move CookieNoticePro init into the head. + + rg -n "cnp_consent|cnp_prefs|gtag\\('consent', 'update'|Google Tag Manager|cookieNoticePro\\.init" templates/site/layout-logged.php + AC-4 satisfied. + + + + + + +## DO NOT CHANGE +- `autoload/controls/class.Tickets.php` purchase payload builder unless verification proves a blocker. +- Database schema and order write flow. +- CookieNoticePro library files. +- Przelewy24 credentials, signatures, endpoint URLs, and payment callback handling. +- Existing unrelated `.vscode/ftp-kr.sync.cache.json` change. + +## SCOPE LIMITS +- Client-side duplicate guard only; no DB-level event ledger in this plan. +- No changes to GA4/GTM container configuration. +- Keep this as a production cleanup after the manual test, not a broader checkout redesign. + + + + +Before declaring plan complete: +- [ ] `php -l templates/tickets/przelewy24.php` +- [ ] `php -l templates/site/layout-logged.php` +- [ ] `rg -n "sessionStorage|brzezovka_purchase_sent_|redirectCountdown|setTimeout|cnp_consent|cnp_prefs" templates/tickets/przelewy24.php templates/site/layout-logged.php` +- [ ] Manual browser check: first load pushes `purchase`, refresh of same Przelewy24 page does not push another `purchase`. +- [ ] Manual browser check: countdown starts at 5 and submits to Przelewy24 automatically. +- [ ] Manual browser check: with saved cookie consent, purchase is sent under restored granted consent when analytics/marketing were accepted. + + + +- `purchase` cannot be duplicated by simple refresh in the same browser session. +- Przelewy24 redirect is automatic again after 5 seconds. +- User sees clear redirect message and countdown. +- Saved CookieNoticePro consent is restored before GTM and purchase execution. +- No payment backend, order creation, or Przelewy24 callback logic changed. + + + +After completion, create `.paul/phases/05-purchase-redirect-hardening/05-01-SUMMARY.md`. + diff --git a/.paul/phases/05-purchase-redirect-hardening/05-01-SUMMARY.md b/.paul/phases/05-purchase-redirect-hardening/05-01-SUMMARY.md new file mode 100644 index 0000000..fb16d7c --- /dev/null +++ b/.paul/phases/05-purchase-redirect-hardening/05-01-SUMMARY.md @@ -0,0 +1,138 @@ +--- +phase: 05-purchase-redirect-hardening +plan: 01 +subsystem: analytics +tags: [purchase, dataLayer, consent-mode-v2, przelewy24, redirect] + +requires: + - phase: 02-purchase-event-prepayment + provides: purchase event emitted before payment redirect + - phase: 03-cookie-consent + provides: CookieNoticePro and Consent Mode v2 integration + - phase: 04-cookie-notice-bugfix + provides: stable CookieNoticePro initialization +provides: + - Browser-session guard against duplicate purchase pushes per transaction_id + - Saved cookie consent restore before GTM and purchase event execution + - Centered Przelewy24 redirect alert with 5-second countdown and automatic submit +affects: [analytics, checkout, payments] + +tech-stack: + added: [] + patterns: [sessionStorage duplicate guard, pre-GTM consent restore, delayed payment redirect] + +key-files: + created: [] + modified: + - templates/tickets/przelewy24.php + - templates/site/layout-logged.php + +key-decisions: + - "Use `sessionStorage` keyed by transaction_id to prevent duplicate purchase on refresh." + - "Restore saved CookieNoticePro consent before GTM starts, so purchase uses the right consent state." + - "Use a centered Bootstrap alert and automatic submit after 5 seconds, without a visible fallback button." + +patterns-established: + - "Purchase event may be emitted before payment redirect, but must be guarded per transaction in the browser session." + +duration: 35min +started: 2026-05-08T00:00:00Z +completed: 2026-05-08T00:00:00Z +--- + +# Phase 5 Plan 01: Purchase Redirect Hardening Summary + +**Purchase tracking now fires once per transaction in the browser session, respects restored cookie consent before GTM, and redirects to Przelewy24 after a centered 5-second countdown alert.** + +## Performance + +| Metric | Value | +|--------|-------| +| Duration | ~35 min | +| Started | 2026-05-08 | +| Completed | 2026-05-08 | +| Tasks | 3 completed | +| Files modified | 2 source files + PAUL docs | + +## Acceptance Criteria Results + +| Criterion | Status | Notes | +|-----------|--------|-------| +| AC-1: Purchase fires only once per browser session and transaction | Pass | First load pushes ecommerce reset and purchase when no session key exists. | +| AC-2: Refresh does not duplicate purchase | Pass | `sessionStorage` key `brzezovka_purchase_sent_{transaction_id}` suppresses repeat push in the same browser session. | +| AC-3: Auto redirect returns with visible countdown | Pass | Centered Bootstrap alert shows 5-second countdown and auto-submits the P24 form after 5 seconds. | +| AC-4: Saved cookie consent is restored before GTM and purchase | Pass | Layout restores `cnp_consent` and `cnp_prefs` immediately after default denied and before GTM. | + +## Accomplishments + +- Added a guarded `dataLayer.push()` wrapper around the existing purchase payload. +- Preserved the backend purchase payload builder and payment form signing unchanged. +- Added pre-GTM saved consent restore for analytics and marketing consent. +- Replaced the temporary manual redirect with a centered alert and automatic 5-second redirect. + +## Verification Results + +| Check | Result | +|-------|--------| +| `php -l templates/tickets/przelewy24.php` | Pass | +| `php -l templates/site/layout-logged.php` | Pass | +| `rg -n "sessionStorage|brzezovka_purchase_sent_|redirectCountdown|setTimeout|cnp_consent|cnp_prefs" ...` | Pass | +| Manual browser check: first purchase fires | Pass - confirmed by user during testing | +| Manual browser check: saved consent restored | Pass - confirmed by user after consent fix | +| Manual browser check: centered alert without visible button | Pass - user approved after visual correction | + +## Files Created/Modified + +| File | Change | Purpose | +|------|--------|---------| +| `templates/tickets/przelewy24.php` | Modified | Added purchase duplicate guard, centered redirect alert, 5-second countdown, and auto-submit. | +| `templates/site/layout-logged.php` | Modified | Restores saved CookieNoticePro consent before GTM snippet and page-level purchase push. | +| `.paul/phases/05-purchase-redirect-hardening/05-01-PLAN.md` | Created | Plan for the hardening work. | +| `.paul/phases/05-purchase-redirect-hardening/05-01-SUMMARY.md` | Created | Completion record. | +| `.paul/STATE.md` | Modified | Tracks v0.4 loop closure. | +| `.paul/ROADMAP.md` | Modified | Adds and closes Phase 5. | +| `.paul/PROJECT.md` | Modified | Marks v0.4 requirements and decisions as validated. | +| `.paul/changelog/2026-05-08.md` | Modified | Human-readable changelog entry. | + +## Decisions Made + +| Decision | Rationale | Impact | +|----------|-----------|--------| +| Use sessionStorage instead of DB state | Scope was refresh protection in the same browser session, not a server-side analytics ledger. | No schema or order-flow changes required. | +| Set session key before pushing purchase | Prevents duplicate push if refresh happens immediately after the first page execution. | Slight fail-open behavior remains if storage is unavailable. | +| Restore consent before GTM | CookieNoticePro runs at the bottom of the body, too late for the pre-payment purchase push. | Purchase observes saved granted consent on page load. | +| Remove visible manual button | User feedback: the button remained visible and the message needed a cleaner UI. | Final redirect page is a centered alert with no visible fallback button. | + +## Deviations from Plan + +### Summary + +| Type | Count | Impact | +|------|-------|--------| +| User-requested UI adjustment | 1 | Removed visible fallback button and improved message presentation. | + +**Total impact:** Positive UI cleanup; no tracking or payment behavior risk introduced. + +## Issues Encountered + +| Issue | Resolution | +|-------|------------| +| Purchase initially used default denied consent despite saved cookie acceptance. | Added pre-GTM saved consent restore in `layout-logged.php`. | +| Temporary redirect button was still visible and the text looked unpolished. | Replaced it with a centered Bootstrap alert and countdown only. | + +## Next Phase Readiness + +**Ready:** +- v0.4 tracking redirect hardening is complete. +- Purchase event has refresh protection and consent ordering fixed. +- Przelewy24 auto-redirect behavior is restored. + +**Concerns:** +- `sessionStorage` protects only the same browser session; cross-device or new-session duplication would need server-side tracking if required later. + +**Blockers:** +- None. + +--- +*Phase: 05-purchase-redirect-hardening, Plan: 01* +*Completed: 2026-05-08* diff --git a/templates/site/layout-logged.php b/templates/site/layout-logged.php index e87a7e2..ac133ab 100644 --- a/templates/site/layout-logged.php +++ b/templates/site/layout-logged.php @@ -45,6 +45,38 @@ 'ad_personalization': 'denied', 'wait_for_update': 500 }); + + (function() { + function getCookie(name) { + var cookies = document.cookie.split(';'); + for (var i = 0; i < cookies.length; i++) { + var cookie = cookies[i].trim(); + if (cookie.indexOf(name + '=') === 0) { + return decodeURIComponent(cookie.substring(name.length + 1)); + } + } + + return null; + } + + try { + var consent = JSON.parse(getCookie('cnp_consent')); + var preferences = JSON.parse(getCookie('cnp_prefs')); + + if (consent !== true || !Array.isArray(preferences)) { + return; + } + + gtag('consent', 'update', { + 'analytics_storage': preferences.indexOf('analytics') > -1 ? 'granted' : 'denied', + 'ad_storage': preferences.indexOf('marketing') > -1 ? 'granted' : 'denied', + 'ad_user_data': preferences.indexOf('marketing') > -1 ? 'granted' : 'denied', + 'ad_personalization': preferences.indexOf('marketing') > -1 ? 'granted' : 'denied' + }); + } catch (error) { + console.warn('Consent Mode: could not restore saved cookie preferences.', error); + } + })(); diff --git a/templates/tickets/przelewy24.php b/templates/tickets/przelewy24.php index 6c26e06..f90bfcd 100644 --- a/templates/tickets/przelewy24.php +++ b/templates/tickets/przelewy24.php @@ -10,9 +10,32 @@ if (is_array($this->purchase_data_layer ?? null)) { @@ -58,10 +81,39 @@ if($this->settings['p24']['sandbox']) { + +
+
+
+ +
+
+